マルチスレッド環境における排他制御 – synchronized修飾子/ブロック
マルチスレッド環境で、共有のデータを操作する際には、処理の競合に注意です。
たとえば以下は、インスタンス変数countを複数のスレッドから同時にインクリメント操作する例ですが、このコードは正しく動作しません。というのも、「this.count++」という演算で、count値が読み出されてからインクリメントして再代入される前に、他のスレッドが割り込む可能性があるためです。そのため、本来、最終的な解は30万になるはずですが、そうはならず、たとえば29988のような値が返されます。
SynchronizedSample.java
- package com.example.mynavi.thread;
- public class SynchronizedSample {
- private int count;
- private static int THREAD_MAX = 300000;
- private static class MyThread implements Runnable {
- private SynchronizedSample _count;
- public MyThread(SynchronizedSample count) {
- this._count = count;
- }
- @Override
- public void run() {
- _count.increment();
- }
- }
- public static void main(String[] args) throws InterruptedException {
- var ss = new SynchronizedSample();
- var ts = new Thread[THREAD_MAX];
- for (var i = 0; i < THREAD_MAX; i++) {
- ts[i] = new Thread(new MyThread(ss));
- ts[i].start();
- }
- for (var i = 0; i < THREAD_MAX; i++) {
- ts[i].join();
- }
- System.out.println(ss.count); // 結果:299944(毎回結果は異なる)
- }
- public void increment() {
- this.count++;
- }
- }
これを防ぐには、incrementメソッドをsynchronized修飾子で修飾します。
SynchronizedSample2.java(抜粋)
- public synchronized void increment() {
- this.count++;
- }
これによって、incrementメソッドは複数のスレッドから同時に呼び出されることがなくなります(後から呼び出した方は、先行する処理が終わるまで待機します)。結果、今度は正しく30万という解が得られます。
ただし、synchronized修飾子が正しく働くのは、メソッドが属するインスタンスが一致している場合です。異なるインスタンスが存在する場合、インスタンスの数だけ同時実行する可能性がありますので、注意してください。
上のコードは、synchronizedブロックを使って、以下のように書き換えることもできます。
SynchronizedSample3.java(抜粋)
- public void increment() {
- synchronized(this) {
- this.count++;
- }
- }
- スレッド_目次
- Threadクラス/Runnableインターフェイス
- synchronized修飾子/ブロック
- ReentrantLockクラス
- AtomicXxxxxクラス
- Executorsクラス
監修
山田祥寛(有限会社 WINGSプロジェクト)
静岡県榛原町生まれ。一橋大学経済学部卒業後、NEC にてシステム企画業務に携わるが、2003年 4 月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト(https://wings.msn.to/)」の代表でもある。主な著書に『改訂 3 版JavaScript 本格入門』(技術評論社)、「独習シリーズ(C#・Python・PHP・Ruby・JSP&サーブレットなど)」(翔泳社)、「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravel など)」(Amazon Kindle)など。売り上げの累計は100万部を超える。