【java】synchronizedはどんな時に使うの?

IT
StartupStockPhotos / Pixabay
スポンサーリンク

synchronizedはどんな時に使うの?ということで、
これまで仕事ではなかなか登場させる機会がありませんでしたので、
いまさらではありますが、今回はjavaのsychronizedを触れてみようと思いました。

synchronizedって?

マルチスレッド処理における排他が必要な処理にて使用します。
synchronizedをつけることによって、あるスレッドがメソッド(またはブロック)を
処理している間、他のスレッドは処理が終わるまで待機することになります。

実際にやってみよう

まず、スレッドにて処理される以下ようなクラスを作成します。

public class ThreadExecutor {

    private int total = 0;

    synchronized public void add(int num) {

        int addResult = total + num;

        // sleepしているのはこれがないと高速で処理が終わってしまうので、
        // thread処理されていることが目に見えて判断しにくいためです。
        try {
            Thread.sleep(1000L);
        } catch (Exception e) {
            e.printStackTrace();
        }

        total = addResult;
    }

    public void print() {
        System.out.println("total is " + total);
    }
}

やっていることは単純です。
クラス変数として合計値のフィールドをもっており、
addメソッドに渡された引数を足しこんでいくというものです。

 

次に以下のように実際にスレッドを生成してThreadExecutorクラスを実行する
クラスを作成します。

public class ThreadSample implements Runnable {

    ThreadExecutor executor;

    public ThreadSample(ThreadExecutor executor) {
        this.executor = executor;
    }

    public static void main(String[] args) {
        // 同一のThreadExecutorクラスを別々のスレッドから使用する
        ThreadExecutor executor = new ThreadExecutor();
        ThreadSample threadSample = new ThreadSample(executor);
        Thread thread1 = new Thread(threadSample);
        Thread thread2 = new Thread(threadSample);

        thread1.start();
        thread2.start();
    }

    @Override
    public void run() {

        for (int i = 0; i < 10; i++) {

            executor.add(1000);
            executor.show();
        }
    }
}

まずはsyncrhonizedをつけないとどうなるのか?

ThreadExecutorクラスのaddメソッドに上記サンプルではsynchronizedがついてますね。
まずはこれをつけないとどうなるのか?

結果はこうなります。

total is 1000
total is 1000
total is 2000
total is 2000
total is 3000
total is 3000
total is 4000
total is 4000
total is 5000
total is 5000
total is 6000
total is 6000
total is 7000
total is 7000
total is 8000
total is 8000
total is 9000
total is 9000
total is 10000
total is 10000

これはまずいですね。
例えばtotalの変数値が自分の銀行口座だとして考えてみましょう。
2箇所のATMから同時にこの口座に1000円ずつ10回お金を振り込んだ
というようなイメージだとわかりやすいかと思います。

本来であれば、20000にならないとおかしいですが、
排他をかけず2つのスレッドがほぼ同時に処理してしまっているので、
合計値の更新がうまくできていないですね。

それではsyncrhonizedをつけてみましょう。

結果はこうなります。

total is 1000
total is 2000
total is 3000
total is 4000
total is 5000
total is 6000
total is 7000
total is 8000
total is 9000
total is 10000
total is 11000
total is 12000
total is 13000
total is 14000
total is 15000
total is 16000
total is 17000
total is 18000
total is 19000
total is 20000

しっかり排他がかかっていて、正しく更新されていますね。

まとめ

このようにsynchronizedをメソッドに付与してあげることで、
処理に排他がかかるということがわかりました。

ブログランキング・にほんブログ村へ
にほんブログ村


人気ブログランキング

コメント

タイトルとURLをコピーしました