$ java -Djava.security.manager Текущий поток: Thread [main, 5, main] Исключение в потоке "main" java.security.AccessControlException: доступ запрещен (java.lang.RuntimePermission modifyThread) в java.security.AccessControlContext.checkPermission (AccessControlContext.java:342) в java.security.AccessController.checkPermission (AccessController.java:553) в java.lang.SecurityManager.checkPerj) в j55.util.concurrent.ThreadPoolExecutor.checkShutdownAccess (ThreadPoolExecutor.java:711) в java.util.concurrent.ThreadPoolExecutor.shutdown (ThreadPoolExecutor.java:1351) в A.main (A.java:22)
Каковы последствия безопасности для создания пула потоков, который
контролируется только вами , и его закрытия?Это ошибка в реализациях, или я что-то упустил?
Давайте посмотрим, что спецификация для ExecutorService.shutdown говорит ...
Инициируетупорядоченное отключение, при котором выполняются ранее представленные задачи, но новые задачи не принимаются.Вызов не имеет никакого дополнительного эффекта, если он уже выключен.
Броски: SecurityException - если менеджер безопасности существует, и закрытие этого ExecutorService может манипулировать потоками, которые вызывающей стороне не разрешено изменять, поскольку он не содержит RuntimePermission ("modifyThread"), или метод checkAccess менеджера безопасности запрещает доступ.
Это ... примерно так неопределенно, как и получается.В спецификации говорится ничего о любых "системных потоках", создаваемых в течение жизненного цикла ExecutorService, и, кроме того, позволяет вам предоставлять свои собственные потоки , что является доказательством того, что должно быть нет «системные потоки», когда вы делаете это.(Как это было сделано выше в моем примере источника)
Такое чувство, что разработчики Java SE увидели, что shutdown
может поднять SecurityException
, поэтому они были просто как, "о хорошо, я просто добавлюслучайная проверка безопасности на соответствие "...
Дело в том, что при чтении из источника OpenJDK (openjdk-6-src-b20-21_jun_2010) получается, что only way любой поток когда-либо создается, вызывая вашу поставляемую ThreadFactory (которая никогда не вызывается в моем тестовом примере, так как я не создаю никакой работы, и я не вызываю prestartCoreThread или prestartAllCoreThreads ).Таким образом, проверка безопасности выполняется без видимой причины в OpenJDK ThreadPoolExecutor (как это делается в sun-jdk-1.6, но у меня нет источника):
/**
* Initiates an orderly shutdown in which previously submitted
* tasks are executed, but no new tasks will be accepted.
* Invocation has no additional effect if already shut down.
*
* @throws SecurityException {@inheritDoc}
*/
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
checkShutdownAccess
вызывается перед тем, как что-либо делать...
/**
* If there is a security manager, makes sure caller has
* permission to shut down threads in general (see shutdownPerm).
* If this passes, additionally makes sure the caller is allowed
* to interrupt each worker thread. This might not be true even if
* first check passed, if the SecurityManager treats some threads
* specially.
*/
private void checkShutdownAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(shutdownPerm);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
security.checkAccess(w.thread);
} finally {
mainLock.unlock();
}
}
}
Как видите, безусловно вызывает checkPermission(shutdownPerm)
в диспетчере безопасности .... shutdownPerm определяется как ... private static final RuntimePermission shutdownPerm =новый RuntimePermission ("modifyThread");
... что, насколько я могу судить, не имеет никакого смысла, потому что modifyThread
подразумевает доступ к системным потокам , а не имеет системных потоков, которые здесь играютНа самом деле нет никаких потоков, потому что я не отправлял ни одной работы или предварительного запуска, и даже если бы были потоки, они были бы моими потоками, потому что я передал ThreadFactory
.В спецификации ничего не говорится о магическом умирании, кроме того, что если задействованы системные потоки (они не участвуют), может быть SecurityException
.
По сути, почему я не могу просто удалитьлиния, которая проверяет доступ к системным потокам?Я не вижу никаких последствий для безопасности, призывающих к этому.И как еще никто не сталкивался с этим вопросом ???Я видел сообщение на трекере, где они «решили» эту проблему, изменив вызов с shutdownNow
на shutdown
, очевидно, что это не помогло.