在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