アプレットのメソッドが同期化されすぎた場合に AWT でデッドロックする


症状

アプレットを Sun JRE を使用したブラウザで実行しているときに、アプレットのメソッド、特に java.awt.Component から継承されたメソッドが同期化されすぎるとデッドロックが発生する場合があります。同じアプレットが Microsoft VM では実行できます。

原因

AWT クラスライブラリは、スレッドに対して安全なクラスライブラリとして使用される場合があります。複数スレッドを使用して AWT を介したアクションを実行するアプレットでは、クラスライブラリで同期化の問題に注意するという前提があります。

しかし、AWT クラスライブラリでスレッドに対して安全であることが保証されるのは、AWT イベントディスパッチスレッドから呼び出しが行われたときのみです。 Microsoft VM と Sun とでは実装が異なるため、スレッドに対して安全でないコードが一方の VM で問題なく実行できても、もう一方では失敗する可能性があります。

アプレットで使用される悪い実例としては、Microsoft VM で競合状態やデッドロックが発生しないように、アプレットの各メソッドを同期化することが挙げられます。しかし、この場合でもデッドロックが発生する可能性があります。

解決方法

この問題を回避するには、本当に必要な箇所でだけアプレットで同期を使用し、不必要な同期は削除します。例を示します。

        public synchronized void paint(Graphics g) {
        ....
    }

    public synchronized void dispose() {       
        super.dispose();
        .....
    }

    public synchronized void stop() {
        ....
    }

    public synchronized void destroy() {
        ....
    }

この場合、paintdisposestop、および destroy メソッドはつねに専用のスレッドから、paint および dispose スレッドは AWT イベントディスパッチスレッドから、stop および destroy メソッドはアプレットのスレッドからそれぞれ呼び出されるため、これらのメソッドの synchronized キーワードは削除します。このコードを次のように変更します。

        public void paint(Graphics g) {
        ....
    }

    public void dispose() {       
        super.dispose();
        .....
    }

    public void stop() {
        ....
    }

    public void destroy() {
        ....
    }

詳細情報

        Java チュートリアルの 「How to Use Threads」 では、スレッドの問題、および AWT と Swing プログラムの両方に適用されるテクニックを説明しています。