Под менеджером безопасности по умолчанию, если создать ExecutorService (ThreadPoolExecutor в данном случае), я не могу закрыть его, shutdown()
просто вызывает checkPermission("modifyThread")
и, таким образом, сразу умирает:Почему я не могу отключить собственный ExecutorService под SecurityManager?
import java.util.concurrent.*;
class A {
public static void main(String[] args) {
Thread ct = Thread.currentThread();
System.out.println("current thread: " + ct);
ct.checkAccess(); // we have access to our own thread...
ThreadPoolExecutor tpe = new ThreadPoolExecutor(
1, // one core thread
1, // doesn't matter because queue is unbounded
0, TimeUnit.SECONDS, // doesn't matter in this case
new LinkedBlockingQueue<Runnable>(), /* unbound queue for
* our single thread */
new ThreadFactory() {
public Thread newThread(Runnable r) {
// obviously never gets called as we don't add any work
System.out.println("making thread");
return new Thread(r);
}
}
);
tpe.shutdown(); // raises security exception
}
}
Sun JDK:
$ java -Djava.security.manager A Текущая тема: Тема [main, 5, main] Исключение в потоке «main» java.security.AccessControlException: доступ запрещен (java.lang.RuntimePermission modifyThread) по адресуjava.security.AccessControlContext.checkPermission (AccessControlContext.java:323) на java.security.AccessController.checkPermission (AccessController.java:546) на java.lang.SecurityManager.checkPermission (SecurityManager.java:532) в java.util.concurrent.ThreadPoolExecutor.shutdown (ThreadPoolExecutor.java:1094) в A.main (A.java:22)
OpenJDK:
$ Java -Djava.security .manager A Текущая тема: Тема [main, 5, main] Исключение в теме "main" java.security.AccessControlException: доступ запрещен (java.lang.RuntimePermission modifyThread) at java.security.AccessControlContext.checkPermission (AccessControlContext.java:342) на java.security.AccessController.checkPermission (AccessController.java:553) в java.lang.SecurityManager.checkPermission (SecurityManager.java:549) в java.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), то получается, что только способ любой нить когда-либо созданных, это, позвонив ThreadFactory (который никогда не вызывается в моем тестовом файле, так как я не создаю никакой работы, и я не звоню prestartCoreThread или preStartAllCoreThreads). Проверка безопасности, таким образом, делается без всякой видимой причины в ThreadPoolExecutor OpenJDK (как это делается в ВС-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 определяется как ... частных статических окончательного RuntimePermission shutdownPerm = новый RuntimePermission ("modifyThread");
... который не имеет абсолютно никакого смысла, насколько я могу сказать, потому что modifyThread
подразумевает доступ к системных потоков, и не никаких системных потоков в игре здесь, на самом деле, нет никаких нитей вообще, потому что Я не подавал никаких работ или предварований, и даже если бы были потоки, они были бы моими потоками, потому что я прошел в ThreadFactory
. Спецификация ничего не говорит о волшебном умирании, кроме этого, если задействованы потоки системы (их нет), может быть SecurityException
.
В принципе, почему я не могу просто удалить строку, которая проверяет доступ к системным потокам? Я не вижу никаких последствий для безопасности, требующих этого. И как никто другой не сталкивался с этой проблемой ??? Я видел сообщение о проблеме, где они «разрешили» эту проблему, изменив звонок на shutdownNow
на shutdown
, очевидно, что это не исправило их.
«[...] он позволяет вам создавать собственные потоки, что является доказательством того, что не должно быть никаких« системных потоков »[...]« Очевидно, что в ваших рассуждениях есть недостаток. Но да, это можно сделать по-другому. Вот как JSR166 определяет API. –
Хмм ... звучит как-то, что, возможно, придется посетить http://bugs.sun.com/ –
@Tom Hawtin: Ах, я не знал, что JSR определили эту часть SE, спасибо, что упомянули об этом. Однако не API, указанный только javadoc в этом JSR? В этом случае он все еще только говорит: «SecurityException - если существует менеджер безопасности и завершение работы этого ExecutorService может работать с потоками, которые вызывающему не разрешено изменять, поскольку он не поддерживает RuntimePermission (« modifyThread ») или метод checkAccess диспетчера безопасности запрещает доступ ». Я не вижу причин для манипулирования потоками системы в моем случае, а checkAccess (Thread) по умолчанию защищает только системные потоки. –