注: この Java 配備ガイドでは、Java SE 6 update 10 リリースより前にリリースされた機能について説明します。最新情報については、Java Rich Internet Application の開発および配備を参照してください。
java.security.AccessControlException
が java.lang.Thread
の stop()
、suspend()
、または resume()
メソッドでスローされるSun Java Runtime Environment (JRE) を使ってブラウザ内でアプレットを実行すると、次のコードに示すように、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
が推奨されない理由