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が推奨されない理由