java.security.AccessControlException
がjava.lang.Thread
のstop
、suspend
、またはresume
メソッドでスローされる
症状アプレットを Sun JRE を使用したブラウザで実行している場合、
AccessControlException
がjava.lang.Thread
のstop
、suspend
、またはresume
メソッドでスローされます。
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 VM では実行できます。原因
この例外は、Sun JRE でこれらのメソッドが死んでいる
Thread
オブジェクト上で呼び出されるために起こります。
Sun JRE の Java クラスライブラリは時間の経過とともに変化してきました。詳細になった API もあれば、廃止された API もあります。また、実装が変更された API もあります。
stop
、suspend
、およびresume
を死んでいるThread
オブジェクト上で呼び出した場合の結果は詳細に定義されていなかったため、Microsoft VM では無操作となります。しかし Sun JRE ではこれらのメソッドを死んでいるThread
オブジェクトで呼び出すと、基礎となる実装の不変部分が意味をなさなくなるため、AccessControlException
がスローされます。解決方法
Thread
のstop
、suspend
、およびresume
メソッドは本質的に安全ではないため、Java 2 プラットフォームでは廃止されました。この問題を回避するには、ターゲットスレッドが停止・中断・再開することを示す変数を変更するコードで、
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 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
メソッドを次のコードで置き換えれば、Thread.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(); } }別の例: アプレットに次のような
mousePressed
イベントハンドラが含まれており、それがblinker
というスレッドの状態を切り替えるとします。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(); }上のイベントハンドラを次のコードで置き換えると、
Thread.suspend
およびThread.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
が推奨されない理由