java線程--最小同步鎖

在java中處理線程併發問題,能夠簡單的加上synchronized,能夠在方法或方法內的代碼塊添加,那如今的問題是,synchronized是鎖住了方法仍是代碼塊仍是實例對象?
加在方法上:java

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結束
能夠看到,上面啓了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時,並不會釋放鎖.this

接下來,把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結束
一樣的道理,這裏的同步鎖是自各的對象實例,3個線程互不影響,沒有互斥做用code

由此得知,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結束
能夠看到,線程同步互斥了io

更好的作法是,直接鎖住這個對象的class對象,與static相同,以下:class

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結束
能夠看到,線程仍然同步互斥

綜上,若須要同步鎖,儘可能最小化同步塊。學習交流,歡迎加羣:64691032

相關文章
相關標籤/搜索