JAvaスレッド--最小同期ロック

3428 ワード

Javaでスレッド同時問題を処理するには、synchronizedを簡単に追加したり、メソッドまたはメソッド内のコードブロックを追加したりすることができます.では、synchronizedはメソッドをロックしたのか、コードブロックをロックしたのか、インスタンスオブジェクトをロックしたのかという問題があります.メソッドに追加:
class Sync {
    public synchronized void test() {
        System.out.println("test  ..");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("test  ..");
    }
}

class MyThread extends Thread {
    public void run() {
        Sync sync = new Sync();
        sync.test();
    }
}

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            Thread thread = new MyThread();
            thread.start();
        }
    }
}

実行結果:testが開始..testが開始..testが開始..testが開始..testが終了..testが終了..testが終了すると、上に3つのスレッドが起動し、各スレッドがsyncをインスタンス化してメソッドを呼び出すので、synchronizedは機能しません.スレッドにはそれぞれの同ステップロックがかかっており、反発はありません.
testメソッドにstaticを付けると、実行結果は以下の通りです.testが開始し、testが終了し、testが開始し、testが終了します.testが開始し、testが終了します.この場合、3つのスレッドの同期ロックはクラスインスタンスではなくSyncクラスオブジェクトです.
public static synchronized void test() {
        System.out.println("test  ..");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("test  ..");
    }

注意:スレッドsleepの場合、ロックは解放されません.
次にsynchronizedをthisに追加します.次のようにします.
public void test() {
     synchronized(this) {
        System.out.println("test  ..");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("test  ..");
    }
}

実行結果:test開始.test開始.test開始.test開始.test終了.test終了.test終了同様、ここでの同期ロックは各オブジェクトインスタンスから行われ、3つのスレッドは互いに影響せず、反発作用はない
このことからsynchronizedはメソッドで鍵をかけたのがオブジェクトインスタンスであり,コードブロックで鍵をかけたのは括弧内のオブジェクトであることが分かった.他のスレッドがロックを取得するには、現在のスレッドの実行が完了し、ロックが解放されるまで待たなければ、オブジェクトに再びロックをかけ、スレッドの同期反発作用を達成できません.スレッドの実行効率を向上させるには、同期コードブロックを最小化し、ロック粒度を最小化します.staticを使用してスレッド反発を実現しましたが、実際には同じオブジェクトでスレッド反発を実現することもできます.以下のようにします.
class MyThread extends Thread {
    private Sync sync;
    public MyThread(Sync sync) {
        this.sync = sync;
    }
    public void run() {
        sync.test();
    }
}

public class Main {
    public static void main(String[] args) {
        Sync sync = new Sync();
        for (int i = 0; i < 3; i++) {
            Thread thread = new MyThread(sync);
            thread.start();
        }
    }
}


実行結果:test開始..test終了..test開始..test終了..test終了..test開始..test終了スレッド同期反発
より良い方法は、このオブジェクトを直接ロックするclassオブジェクトがstaticと同じで、以下のようになります.
class Sync {
    public void test() {
        synchronized (Sync.class) {
            System.out.println("test  ..");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("test  ..");
        }
    }
}

class MyThread extends Thread {
    public void run() {
        Sync sync = new Sync();
        sync.test();
    }
}

実行結果:test開始..test終了..test開始..test終了..test終了..test開始..test終了スレッドが同期して反発していることがわかります
以上、同期ロックが必要であれば、できるだけ同期ブロックを最小化する.学習交流、歓迎加群:64691032