デフォルトのセキュリティ マネージャーでは、ExecutorService (この場合はThreadPoolExecutor ) を作成すると、それをシャットダウンできず、shutdown()
呼び出すだけですぐに終了しますcheckPermission("modifyThread")
。
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
}
}
サンJDK:
$ java -Djava.security.manager 現在のスレッド: Thread[main,5,main] Exception in thread "main" java.security.AccessControlException: access denied (java.lang.RuntimePermission modifyThread) at 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 現在のスレッド: Thread[main,5,main] Exception in thread "main" java.security.AccessControlException: access denied (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を呼び出しません)。したがって、セキュリティ チェックは、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 = new RuntimePermission("modifyThread");
...システムスレッドmodifyThread
へのアクセスを意味するため、私が知る限り、これはまったく意味がありません。また、ここではシステムスレッドが実行されていません。実際、作業や事前開始を送信しなかったため、スレッドはまったくありません、スレッドがあったとしても、.を渡したので、それらは私のスレッドになります。システムスレッドが関与している場合(関与していない場合)、.ThreadFactory
SecurityException
基本的に、システム スレッドへのアクセスをチェックする行を削除できないのはなぜですか? それを必要とするセキュリティ上の意味はありません。そして、他の誰もこの問題に出くわしたのはどうしてですか??? への呼び出しを変更することでこの問題を「解決」した問題トラッカーの投稿を見たことがありますがshutdownNow
、shutdown
明らかに修正されませんでした。