java.security.AccessControlException
がjava.lang.Thread
のstop()
、suspend()
、またはresume()
メソッドでスローされる
症状Sun JavaTM Runtime Environment (JRETM) を使ってブラウザ内でアプレットを実行すると、次のコードに示すように、
java.lang.Thread
クラスのstop
、suspend
、またはresume
メソッドでjava.security.AccessControlException
がスローされます。
java.security.AccessControlException:access denied (java.lang.RuntimePermission modifyThread)
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
at sun.applet.AppletSecurity.checkAccess(Unknown Source)
at java.lang.Thread.checkAccess(Unknown Source)
at java.lang.Thread.stop(Unknown Source)
at ....
同じアプレットが、Microsoft Virtual Machine (VM) では何のエラーもなく実行されます。原因
この例外は、Sun JRE でこれらのメソッドが死んでいる
Thread
オブジェクト上で呼び出されたときに起こります。
Sun JRE の Java クラスライブラリは時間の経過とともに変化してきました。詳細になった API もあれば、廃止された API もあります。また、実装が変更された API もあります。デッド
Thread
オブジェクトのstop
、suspend
、およびresume
を呼び出した場合の結果は、明確に定義されていませんでした。Microsoft VM の場合、それらは無操作になります。しかし Sun JRE ではこれらのメソッドを死んでいるThread
オブジェクトで呼び出すと、基礎となる実装の不変表現が意味をなさなくなるため、java.security.AccessControlException
がスローされます。解決方法
Thread
のstop
、suspend
、およびresume
メソッドは本質的に安全ではないため、Java テクノロジでは廃止されました。
stop
、suspend
、およびresume
への呼び出しを、対象スレッドで停止、中断、再開のいずれを行うべきかを示す変数を変更するコードで置き換えます。
次の例では、stop、suspend、および resume メソッドを代替コードで置き換える方法を示します。
たとえば、アプレットに次のメソッドが含まれているとします。
private Thread blinker; public void start() { blinker = new Thread(this); blinker.start(); } public void stop() { blinker.stop(); // UNSAFE! }public void destroy() { blinker.stop(); // UNSAFE and WILL throw java.security.AccessControlException in the Sun JRE! } public void run() { Thread thisThread = Thread.currentThread(); while (true) { try { thisThread.sleep(interval); } catch (InterruptedException e){ } repaint(); } }アプレットの
stop
、destroy
、およびrun
メソッドを次のコードに示すように変更すれば、blinker.stop
を使用しないで済みます。private volatile Thread blinker; public void stop() { blinker = null; } public void destroy() { blinker = null; } public void run() { Thread thisThread = Thread.currentThread(); while (blinker == thisThread) { try { thisThread.sleep(interval); } catch (InterruptedException e){ } repaint(); } }たとえば、次のコードに示すように、
blinker
という名前のスレッドの状態を切り替えるmousePressed
イベントハンドラを含むアプレットがあるとします。private boolean threadSuspended; public void mousePressed(MouseEvent e) { e.consume(); if (threadSuspended) blinker.resume(); else blinker.suspend(); // DEADLOCK-PRONE! threadSuspended = !threadSuspended; } public void run() { while (true) { try { Thread.currentThread().sleep(interval); } catch (InterruptedException e){ } repaint(); }イベントハンドラを次のコードで置き換えると、
blinker.suspend
およびblinker.resume
を使わなくて済みます。private boolean volatile threadSuspended; public synchronized void mousePressed(MouseEvent e) { e.consume(); threadSuspended = !threadSuspended; if (!threadSuspended) notify(); } public void run() { while (true) { try { Thread.currentThread().sleep(interval); if (threadSuspended) { synchronized(this) { while (threadSuspended) wait(); } } } catch (InterruptedException e){ } repaint(); } }詳細情報
Thread.stop
、Thread.suspend
、Thread.resume
、およびRuntime.runFinalizersOnExit
が推奨されない理由