javaマルチスレッドの安全問題


複数のスレッドが同時に共有され、同じグローバル変数または静的変数が書き込みの動作をすると、データ衝突問題、すなわちスレッドセキュリティ問題が発生する可能性があります。しかし、読み操作をすると、データの衝突が発生しません。
模擬スレッドの安全問題
public class SafeThread implements Runnable {

    private int ticketCount = 50;

    @Override
    public void run() {
        while (ticketCount > 0) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ",   " + (50 - ticketCount + 1) + "  ");
            ticketCount--;
        }
    }
}
@RequestMapping("test-safe")
    public void testSafe() {
        SafeThread safeThread = new SafeThread();
        Thread t1 = new Thread(safeThread, "thread-1");
        Thread t2 = new Thread(safeThread, "thread-2");
        t1.start();
        t2.start();
    }
結果:列車の切符は繰り返し販売されます。
解決策
マルチスレッド間でsynchronizedを同期するか、ロック(lock)1を使うか、同期コードブロック
public class SafeThread implements Runnable {

    private int ticketCount = 50;

    @Override
    public void run() {
        while (ticketCount > 0) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (this) {
                System.out.println(Thread.currentThread().getName() + ",   " + (50 - ticketCount + 1) + "  ");
                ticketCount--;
            }
        }
    }
}
2.同期方法
public class SafeThread implements Runnable {

    private int ticketCount = 50;

    @Override
    public void run() {
        while (ticketCount > 0) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
//            synchronized (this) {
//                System.out.println(Thread.currentThread().getName() + ",   " + (50 - ticketCount + 1) + "  ");
//                ticketCount--;
//            }
            sale();
        }
    }

    private synchronized void sale() {
        System.out.println(Thread.currentThread().getName() + ",   " + (50 - ticketCount + 1) + "  ");
        ticketCount--;
    }
}
注意:同期関数はthisロックを使用します。
3.静的同期関数方法にstaticキーワードを加え、synchronizedキーワードを使ってクラスを修飾したり、クラス.classファイルを使ったりします。静的な同期関数で使用されるロックは、この関数が属するバイトコードファイルオブジェクトであり、get Class方法で取得できます。また、現在のクラス名でもいいです。クラス名で表します。
public class SafeThread implements Runnable {

    private int ticketCount = 50;

    @Override
    public void run() {
        while (ticketCount > 0) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
//            synchronized (this) {
//                System.out.println(Thread.currentThread().getName() + ",   " + (50 - ticketCount + 1) + "  ");
//                ticketCount--;
//            }
//            sale();
            sale2();
        }
    }

    private synchronized void sale() {
        System.out.println(Thread.currentThread().getName() + ",   " + (50 - ticketCount + 1) + "  ");
        ticketCount--;
    }


    private void sale2() {
        synchronized (SafeThread.class) {
            System.out.println(Thread.currentThread().getName() + ",   " + (50 - ticketCount + 1) + "  ");
            ticketCount--;
        }
    }
}
デッドロック問題
同期中に入れ子が同期してしまい、ロックが解除できなくなりました。同期中に入れ子が同期しないようにしてください。