Javaマルチスレッド探究-スレッド同期

6738 ワード

スレッド同期とは
スレッド同期は、複数のスレッドが同時に同じデータを操作することによるデータ破壊を解決することであり、前述したチケットの例のように、-1を売るチケットが現れ、問題が発生する
スレッド同期方式
1.synchronizedキーワード
1.1同期方法
便利な宣言にsynchronizedを加えると、この方法は同期され、毎回1つのスレッドだけが方法のコードを実行することができ、このスレッドが方法から離れていない場合、他のスレッドはブロック状態になるしかなく、データを操作する1回に1つのスレッドしかないことを保証します.
class MyRunnable implements   Runnable{
    private int ticket = 100;

    @Override
    public  void run(){
            salseTicket();
    }
    public synchronized void salseTicket(){
        while (true){
            if(ticket > 0){
                try {
                    Thread.sleep(5);
                    System.out.println("   "+Thread.currentThread().getName()+" sales "+ticket--);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }else{
                break;
            }
        }
    }

}
public class ThreadDemo {

    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread t1 = new Thread(runnable,"one");
        Thread t2 = new Thread(runnable,"two");
        Thread t3 = new Thread(runnable,"third");
        Thread t4 = new Thread(runnable,"four");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

1.2. 同期コードブロック
同期コードブロックは同期方法とは異なり、同期コードブロックは一部のコードのみをロックします.これにより、メソッド全体よりもロック効率が高くなります.私たちのチケット販売プログラムでは主に最もtickeです.この操作は原子操作ではありません.各スレッドが印刷とtickeを実行することを保証しなければなりません.他のスレッドが入ってきて同期コードブロックを実行することを許可するにはロックが必要です.このロックはオブジェクトロックです.同期するスレッドについては、同期を保証するために必要なロックが一致しています.たとえば、次の例のオブジェクトロックはthisです.このthisはMyRunnableの参照です.1部しかありません.各スレッドが所有しているので、同期を行うことができます.
class MyRunnable implements Runnable {
    private int ticket = 100;

    @Override
    public void run() {
        salseTicket();
    }

    public void salseTicket() {
        while (true) {
            synchronized (this) {//     
                if (ticket > 0) {
                    try {
                        Thread.sleep(5);
                        System.out.println("   " + Thread.currentThread().getName() + " sales " + ticket--);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    break;
                }
            }
        }
    }
}

次のオブジェクトロックnew Object()を考えてみましょう.これにより、オブジェクトロックが追加されているにもかかわらず、スレッドが新しいObjectオブジェクトを所有している場合、このロックメカニズムは失効し、同期の役割を果たしません.
synchronized (new Object()) {
    if (ticket > 0) {
        try {
            Thread.sleep(5);
            System.out.println("   " + Thread.currentThread().getName() + " sales " + ticket--);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    } else {
        break;
    }
}

クラスロックは、オブジェクトロックの他に、コードブロックが存在する方法が静的方法である場合、synchronizedのロックはthisではなくクラスであるべきである.静的メソッドにはオブジェクトのthis参照がないことはよく知られていますが、次のプログラムはクラスロックです.
public static  void salseTicket() {
    while (true) {
        synchronized (MyRunnable.class) {
            if (ticket > 0) {
                try {
                    Thread.sleep(5);
                    System.out.println("   " + Thread.currentThread().getName() + " sales " + ticket--);

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                break;
            }
        }
    }
}