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