Java
 Computer >> コンピューター >  >> プログラミング >> Java

Javaのrun()メソッドは同期化できる?synchronizedの必要性と動作を解説

結論:run()メソッドは同期化できる

はい、Javaのrun()メソッドにもsynchronizedキーワードを付けて同期化することは可能です。

ただし、通常の使い方ではrun()メソッドは1つのスレッドによってのみ実行されるため、あえて同期化する必要はありません。同期化が本来求められるのは、複数のスレッドから同時に呼び出される可能性がある他クラスの非staticメソッドです。

一方で、後述のサンプルのように同じRunnableインスタンスを複数のスレッドで共有する場合には、synchronizedを付けることに実際的な意味が生まれます。非staticメソッドの同期化はインスタンス自身(this)に対してロックを取得する仕組みのため、あるスレッドがrun()メソッドを実行している間、他のスレッドはその完了を待たされることになります。

サンプルコード

public class SynchronizeRunMethodTest implements Runnable {
    public synchronized void run() {
        System.out.println(Thread.currentThread().getName() + " is starting");
        for(int i=0; i < 5; i++) {
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + " is running");
            } catch(InterruptedException ie) {
                ie.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + " is finished");
    }
    public static void main(String[] args) {
        SynchronizeRunMethodTest test = new SynchronizeRunMethodTest();
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(test);
        t1.start();
        t2.start();
    }
}

この例では、単一のSynchronizeRunMethodTestインスタンスをt1とt2という2つのスレッドで共有しています。run()メソッドにはsynchronizedが付与されているため、先にロックを獲得したスレッドが一連の処理を完了するまで、もう一方のスレッドは待機します。

実行結果

Thread-0 is starting
Thread-0 is running
Thread-0 is running
Thread-0 is running
Thread-0 is running
Thread-0 is running
Thread-0 is finished
Thread-1 is starting
Thread-1 is running
Thread-1 is running
Thread-1 is running
Thread-1 is running
Thread-1 is running
Thread-1 is finished

実行結果のポイント

出力を見ると、Thread-0が「starting」から「finished」までの一連の処理を完全に終えた後で、Thread-1が処理を開始していることが分かります。これがsynchronizedによる排他制御が正しく機能している証拠です。

もしsynchronizedを外した場合、2つのスレッドが並行してrun()メソッドを実行するため、「Thread-0 is running」と「Thread-1 is running」の出力が交互に混ざり合うことになります。この違いを比較してみると、インスタンス共有時における同期化の効果がより明確に理解できるでしょう。

  1. Javaのpack()メソッドとは?使い方とsetSize()との違いを解説

    pack()メソッドは、JavaのWindowクラスで定義されているメソッドで、フレーム内のすべてのコンポーネントがそれぞれの推奨サイズ(preferred size)以上で表示されるように、ウィンドウのサイズを自動的に調整します。 代替手段として、setSize()メソッドやsetBounds()メソッドを呼び出して、フレームのサイズを明示的に指定する方法もあります。しかし一般的には、pack()メソッドを使用する方がsetSize()よりも推奨されています。その理由は、pack()がフレームのサイズ決定をレイアウトマネージャーに委ねることができ、レイアウトマネージャーはプラットフォーム間の

  2. JavaのSwingUtilities.invokeLater()メソッドの使い方を徹底解説

    invokeLater()メソッドとはinvokeLater()メソッドは、SwingUtilitiesクラスが提供するstaticメソッドの一つで、AWTイベントディスパッチスレッド(Event Dispatch Thread)上でタスクを非同期に実行するために使用されます。このメソッドはSwingUtilities.invokeAndWait()とよく似た動作をしますが、大きな違いは、処理のリクエストをイベントキューに登録した後、すぐに呼び出し元へ制御を返すという点です。つまり、invokeLater()は引数で渡されたRunnableオブジェクト内のコードブロックの実行完了を待ちません。