[Java マルチスレッド] 同期されたコード ブロックはスレッド セーフティの問題を処理します

質問: チケットを販売するウィンドウを 3 つ作成し、チケットの総数は 100 です
1. 質問: チケットを購入するプロセス中に、重複したチケットと間違ったチケットが存在します --> スレッドのセキュリティの問題があります 2.
理由問題点: スレッドがチケットを操作する過程で、操作が完了していない場合、他のスレッドが参加してチケットを操作する場合 3. 解決方法: スレッド a がチケットを操作しているとき、他のスレッドは参加できませ
んスレッド a がチケットの操作を完了するまで、
  他のスレッドはチケットの操作を開始できません。この場合、スレッド a がブロックされても変更できません。
生活の中でのことを例に挙げてみましょう。
あなたがトイレに行こうとすると、別の人が急いであなたのいるトイレに駆け込みます。これにはセキュリティ上の問題が生じます。どのように解決すればよいでしょうか? 
答え: トイレのドアをロックします。 4. Java では、同期メカニズムを使用してスレッドのセキュリティ問題を解決します。
================================================= == ========================================  方法 1: 同期コード ブロックの同期 ( synchronization Monitor) { 
       //同期が必要なコード
   }
   説明: 1. 共有データ上で動作するコードは、同期が必要なコードです。
         2. 共有データ: 複数のスレッドが一緒に動作する変数。例: チケットは共有データです。
         3. 同期モニター。通称:ロック。どのクラスのオブジェクトもロック要件として機能できます。複数のスレッドが同じロックを共有する必要があります。


   
           

 

同期されたコード ブロックは、Runnable の実装に伴うスレッド セーフティの問題を処理します。

コードは以下のように表示されます。

class Window1 implements Runnable{

    private int ticket = 100;
    Object obj = new Object();
    @Override
    public void run() {
        while (true){
            synchronized (obj) {
                if (ticket > 0){
                    System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticket--;
                }else {
                    break;
                }
            }
        }
    }
}
public class WindowTest1{
    public static void main(String[] args) {
        Window1 w = new Window1();

        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();

    }
}

 複数回の実行によると、間違ったチケットや重複したチケットは見つかりませんでした。

同期されたコード ブロックは、Thread クラスから継承されたスレッド セーフティの問題を処理します

まず上記の方法を模倣してテストを実行します。

コードは以下のように表示されます。


class Window extends Thread{
    private static int ticket = 100;
    private Object obj = new Object();
    @Override
    public void run() {
        while (true){
            synchronized (obj){
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName() + "卖票,票号为:" + ticket);
                    ticket --;
                }else {
                    break;
                }
            }
        }
    }
}
public class WindowTest {
    public static void main(String[] args) {
        Window t1 = new Window();
        Window t2 = new Window();
        Window t3 = new Window();

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();

    }
}
図に示すように、

依然として重いチケットがあることがわかります。上に書いてあるからです。要件: 複数のスレッドが同じロックを共有する必要がある
ため、
以下に示すように静的コードを追加できます。
class Window extends Thread{
    private static int ticket = 100;
    private static Object obj = new Object();
    @Override
    public void run() {
        while (true){
            synchronized (obj){
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName() + "卖票,票号为:" + ticket);
                    ticket --;
                }else {
                    break;
                }
            }
        }
    }
}
public class WindowTest {
    public static void main(String[] args) {
        Window t1 = new Window();
        Window t2 = new Window();
        Window t3 = new Window();

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();

    }
}
走行には問題ありません。
================================================= == ========================================= 
「要件: マルチスレッド」を参照してください。Runnable を実装する際のスレッド セーフティの問題に対処するには、同期コード ブロック内で同じ「Put the lock」を共有する必要があります。現時点では、同期モニターを「this」(Window1 の唯一のオブジェクト) に変更できます。

class Window1 implements Runnable{

    private int ticket = 100;
    Object obj = new Object();
    @Override
    public void run() {
        while (true){
            synchronized (this){//此时的this:唯一的Window1的对象 synchronized (obj) {
                if (ticket > 0){
                    System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticket--;
                }else {
                    break;
                }
            }
        }
    }
}
public class WindowTest1{
    public static void main(String[] args) {
        Window1 w = new Window1();

        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();

    }
}
Thread クラスの継承によるスレッド セーフティの問題に対処するために、同期コード ブロック内で同期モニターも "this" に変更できるかどうかを
検討してください。
次の図に示すように、ウィンドウは 3 つのオブジェクトを作成するため、同期モニターを変更することはできません。これに変更されました。ただし、同期モニターを「Window.class」に変更するという簡単な方法もあります。
synchronized (Window.class){
}
================================================= == ========================================
概要:
この同期方法は、既存の問題を解決します。セキュリティの問題。---利点
同期コードを操作する場合、1 つのスレッドのみが参加でき、他のスレッドは待機します。これは、効率の低いシングルスレッド プロセスと同等です。--- 制限事項ご覧いただきありがとうございます。

 

 

おすすめ

転載: blog.csdn.net/qq_64976935/article/details/128879882