Synchronized 的 8 種用法,真是絕了!

2021-02-07 Java研發軍團
簡介

本文將介紹8種同步方法的訪問場景,我們來看看這8種情況下,多線程訪問同步方法是否還是線程安全的。這些場景是多線程編程中經常遇到的,而且也是面試時高頻被問到的問題,所以不管是理論還是實踐,這些都是多線程場景必須要掌握的場景。

八種使用場景:

接下來,我們來通過代碼實現,分別判斷以下場景是不是線程安全的,以及原因是什麼。

兩個線程分別同時訪問(一個或兩個)對象的同步方法和非同步方法

兩個線程訪問同一個對象中的同步方法,同步方法又調用一個非同步方法

兩個線程分別同時訪問靜態synchronized和非靜態synchronized方法

場景一:兩個線程同時訪問同一個對象的同步方法

分析:這種情況是經典的對象鎖中的方法鎖,兩個線程爭奪同一個對象鎖,所以會相互等待,是線程安全的。

「兩個線程同時訪問同一個對象的同步方法,是線程安全的。」

場景二:兩個線程同時訪問兩個對象的同步方法

這種場景就是對象鎖失效的場景,原因出在訪問的是兩個對象的同步方法,那麼這兩個線程分別持有的兩個線程的鎖,所以是互相不會受限的。加鎖的目的是為了讓多個線程競爭同一把鎖,而這種情況多個線程之間不再競爭同一把鎖,而是分別持有一把鎖,所以我們的結論是:

「兩個線程同時訪問兩個對象的同步方法,是線程不安全的。」

代碼驗證:
public class Condition2 implements Runnable {  
    // 創建兩個不同的對象  
 static Condition2 instance1 = new Condition2();  
 static Condition2 instance2 = new Condition2();  
  
 @Override  
 public void run() {  
  method();  
 }  
  
 private synchronized void method() {  
  System.out.println("線程名:" + Thread.currentThread().getName() + ",運行開始");  
  try {  
   Thread.sleep(4000);  
  } catch (InterruptedException e) {  
   e.printStackTrace();  
  }  
  System.out.println("線程:" + Thread.currentThread().getName() + ",運行結束");  
 }  
  
 public static void main(String[] args) {  
  Thread thread1 = new Thread(instance1);  
  Thread thread2 = new Thread(instance2);  
  thread1.start();  
  thread2.start();  
  while (thread1.isAlive() || thread2.isAlive()) {  
  }  
  System.out.println("測試結束");  
 }  
}  
 

運行結果:

兩個線程是並行執行的,所以線程不安全。

線程名:Thread-0,運行開始  
線程名:Thread-1,運行開始  
線程:Thread-0,運行結束  
線程:Thread-1,運行結束  
測試結束  
 

代碼分析:

「問題在此:」

兩個線程(thread1、thread2),訪問兩個對象(instance1、instance2)的同步方法(method()),兩個線程都有各自的鎖,不能形成兩個線程競爭一把鎖的局勢,所以這時,synchronized修飾的方法method()和不用synchronized修飾的效果一樣(不信去把synchronized關鍵字去掉,運行結果一樣),所以此時的method()只是個普通方法。

「如何解決這個問題:」

若要使鎖生效,只需將method()方法用static修飾,這樣就形成了類鎖,多個實例(instance1、instance2)共同競爭一把類鎖,就可以使兩個線程串行執行了。這也就是下一個場景要講的內容。

場景三:兩個線程同時訪問(一個或兩個)對象的靜態同步方法

這個場景解決的是場景二中出現的線程不安全問題,即用類鎖實現:

「兩個線程同時訪問(一個或兩個)對象的靜態同步方法,是線程安全的。」

場景四:兩個線程分別同時訪問(一個或兩個)對象的同步方法和非同步方法

這個場景是兩個線程其中一個訪問同步方法,另一個訪問非同步方法,此時程序會不會串行執行呢,也就是說是不是線程安全的呢?
我們可以確定是線程不安全的,如果方法不加synchronized都是安全的,那就不需要同步方法了。驗證下我們的結論:

「兩個線程分別同時訪問(一個或兩個)對象的同步方法和非同步方法,是線程不安全的。」

public class Condition4 implements Runnable {  
  
 static Condition4 instance = new Condition4();  
  
 @Override  
 public void run() {  
  //兩個線程訪問同步方法和非同步方法  
  if (Thread.currentThread().getName().equals("Thread-0")) {  
   //線程0,執行同步方法method0()  
   method0();  
  }  
  if (Thread.currentThread().getName().equals("Thread-1")) {  
   //線程1,執行非同步方法method1()  
   method1();  
  }  
 }  
      
    // 同步方法  
 private synchronized void method0() {  
  System.out.println("線程名:" + Thread.currentThread().getName() + ",同步方法,運行開始");  
  try {  
   Thread.sleep(4000);  
  } catch (InterruptedException e) {  
   e.printStackTrace();  
  }  
  System.out.println("線程:" + Thread.currentThread().getName() + ",同步方法,運行結束");  
 }  
      
    // 普通方法  
 private void method1() {  
  System.out.println("線程名:" + Thread.currentThread().getName() + ",普通方法,運行開始");  
  try {  
   Thread.sleep(4000);  
  } catch (InterruptedException e) {  
   e.printStackTrace();  
  }  
  System.out.println("線程:" + Thread.currentThread().getName() + ",普通方法,運行結束");  
 }  
  
 public static void main(String[] args) {  
  Thread thread1 = new Thread(instance);  
  Thread thread2 = new Thread(instance);  
  thread1.start();  
  thread2.start();  
  while (thread1.isAlive() || thread2.isAlive()) {  
  }  
  System.out.println("測試結束");  
 }  
  
}  
 

運行結果:

兩個線程是並行執行的,所以是線程不安全的。

線程名:Thread-0,同步方法,運行開始  
線程名:Thread-1,普通方法,運行開始  
線程:Thread-0,同步方法,運行結束  
線程:Thread-1,普通方法,運行結束  
測試結束  
 

結果分析

問題在於此:method1沒有被synchronized修飾,所以不會受到鎖的影響。即便是在同一個對象中,當然在多個實例中,更不會被鎖影響了。結論:

「非同步方法不受其它由synchronized修飾的同步方法影響」

你可能想到一個類似場景:多個線程訪問同一個對象中的同步方法,同步方法又調用一個非同步方法,這個場景會是線程安全的嗎?

場景五:兩個線程訪問同一個對象中的同步方法,同步方法又調用一個非同步方法

我們來實驗下這個場景,用兩個線程調用同步方法,在同步方法中調用普通方法;再用一個線程直接調用普通方法,看看是否是線程安全的?

public class Condition8 implements Runnable {  
  
 static Condition8 instance = new Condition8();  
  
 @Override  
 public void run() {  
  if (Thread.currentThread().getName().equals("Thread-0")) {  
   //直接調用普通方法  
   method2();  
  } else {  
   // 先調用同步方法,在同步方法內調用普通方法  
   method1();  
  }  
 }  
  
 // 同步方法  
 private static synchronized void method1() {  
  System.out.println("線程名:" + Thread.currentThread().getName() + ",同步方法,運行開始");  
  try {  
   Thread.sleep(2000);  
  } catch (InterruptedException e) {  
   e.printStackTrace();  
  }  
  System.out.println("線程:" + Thread.currentThread().getName() + ",同步方法,運行結束,開始調用普通方法");  
  method2();  
 }  
  
 // 普通方法  
 private static void method2() {  
  System.out.println("線程名:" + Thread.currentThread().getName() + ",普通方法,運行開始");  
  try {  
   Thread.sleep(4000);  
  } catch (InterruptedException e) {  
   e.printStackTrace();  
  }  
  System.out.println("線程:" + Thread.currentThread().getName() + ",普通方法,運行結束");  
 }  
  
 public static void main(String[] args) {  
  // 此線程直接調用普通方法  
  Thread thread0 = new Thread(instance);  
  // 這兩個線程直接調用同步方法  
  Thread thread1 = new Thread(instance);  
  Thread thread2 = new Thread(instance);  
  thread0.start();  
  thread1.start();  
  thread2.start();  
  while (thread0.isAlive() || thread1.isAlive() || thread2.isAlive()) {  
  }  
  System.out.println("測試結束");  
 }  
  
}  
 

運行結果:
線程名:Thread-0,普通方法,運行開始  
線程名:Thread-1,同步方法,運行開始  
線程:Thread-1,同步方法,運行結束,開始調用普通方法  
線程名:Thread-1,普通方法,運行開始  
線程:Thread-0,普通方法,運行結束  
線程:Thread-1,普通方法,運行結束  
線程名:Thread-2,同步方法,運行開始  
線程:Thread-2,同步方法,運行結束,開始調用普通方法  
線程名:Thread-2,普通方法,運行開始  
線程:Thread-2,普通方法,運行結束  
測試結束  
 

結果分析:

我們可以看出,普通方法被兩個線程並行執行,不是線程安全的。這是為什麼呢?

因為如果非同步方法,有任何其他線程直接調用,而不是僅在調用同步方法時,才調用非同步方法,此時會出現多個線程並行執行非同步方法的情況,線程就不安全了。

對於同步方法中調用非同步方法時,要想保證線程安全,就必須保證非同步方法的入口,僅出現在同步方法中。但這種控制方式不夠優雅,若被不明情況的人直接調用非同步方法,就會導致原有的線程同步不再安全。所以不推薦大家在項目中這樣使用,但我們要理解這種情況,並且我們要用語義明確的、讓人一看就知道這是同步方法的方式,來處理線程安全的問題。

所以,最簡單的方式,是在非同步方法上,也加上synchronized關鍵字,使其變成一個同步方法,這樣就變成了《場景五:兩個線程同時訪問同一個對象的不同的同步方法》,這種場景下,大家就很清楚的看到,同一個對象中的兩個同步方法,不管哪個線程調用,都是線程安全的了。

所以結論是:

「兩個線程訪問同一個對象中的同步方法,同步方法又調用一個非同步方法,僅在沒有其他線程直接調用非同步方法的情況下,是線程安全的。若有其他線程直接調用非同步方法,則是線程不安全的。」

場景六:兩個線程同時訪問同一個對象的不同的同步方法

這個場景也是在探討對象鎖的作用範圍,對象鎖的作用範圍是對象中的所有同步方法。所以,當訪問同一個對象中的多個同步方法時,結論是:

「兩個線程同時訪問同一個對象的不同的同步方法時,是線程安全的。」

public class Condition5 implements Runnable {  
 static Condition5 instance = new Condition5();  
  
 @Override  
 public void run() {  
  if (Thread.currentThread().getName().equals("Thread-0")) {  
   //線程0,執行同步方法method0()  
   method0();  
  }  
  if (Thread.currentThread().getName().equals("Thread-1")) {  
   //線程1,執行同步方法method1()  
   method1();  
  }  
 }  
  
 private synchronized void method0() {  
  System.out.println("線程名:" + Thread.currentThread().getName() + ",同步方法0,運行開始");  
  try {  
   Thread.sleep(4000);  
  } catch (InterruptedException e) {  
   e.printStackTrace();  
  }  
  System.out.println("線程:" + Thread.currentThread().getName() + ",同步方法0,運行結束");  
 }  
  
 private synchronized void method1() {  
  System.out.println("線程名:" + Thread.currentThread().getName() + ",同步方法1,運行開始");  
  try {  
   Thread.sleep(4000);  
  } catch (InterruptedException e) {  
   e.printStackTrace();  
  }  
  System.out.println("線程:" + Thread.currentThread().getName() + ",同步方法1,運行結束");  
 }  
  
 //運行結果:串行  
 public static void main(String[] args) {  
  Thread thread1 = new Thread(instance);  
  Thread thread2 = new Thread(instance);  
  thread1.start();  
  thread2.start();  
  while (thread1.isAlive() || thread2.isAlive()) {  
  }  
  System.out.println("測試結束");  
 }  
}  
 

運行結果:

是線程安全的。

線程名:Thread-1,同步方法1,運行開始  
線程:Thread-1,同步方法1,運行結束  
線程名:Thread-0,同步方法0,運行開始  
線程:Thread-0,同步方法0,運行結束  
測試結束  
 

結果分析:

兩個方法(method0()和method1())的synchronized修飾符,雖沒有指定鎖對象,但默認鎖對象為this對象為鎖對象,
所以對於同一個實例(instance),兩個線程拿到的鎖是同一把鎖,此時同步方法會串行執行。這也是synchronized關鍵字的可重入性的一種體現。

場景七:兩個線程分別同時訪問靜態synchronized和非靜態synchronized方法

這種場景的本質也是在探討兩個線程獲取的是不是同一把鎖的問題。靜態synchronized方法屬於類鎖,鎖對象是(*.class)對象,非靜態synchronized方法屬於對象鎖中的方法鎖,鎖對象是this對象。兩個線程拿到的是不同的鎖,自然不會相互影響。結論:

「兩個線程分別同時訪問靜態synchronized和非靜態synchronized方法,線程不安全。」

代碼實現:
public class Condition6 implements Runnable {  
 static Condition6 instance = new Condition6();  
  
 @Override  
 public void run() {  
  if (Thread.currentThread().getName().equals("Thread-0")) {  
   //線程0,執行靜態同步方法method0()  
   method0();  
  }  
  if (Thread.currentThread().getName().equals("Thread-1")) {  
   //線程1,執行非靜態同步方法method1()  
   method1();  
  }  
 }  
  
 // 重點:用static synchronized 修飾的方法,屬於類鎖,鎖對象為(*.class)對象。  
 private static synchronized void method0() {  
  System.out.println("線程名:" + Thread.currentThread().getName() + ",靜態同步方法0,運行開始");  
  try {  
   Thread.sleep(4000);  
  } catch (InterruptedException e) {  
   e.printStackTrace();  
  }  
  System.out.println("線程:" + Thread.currentThread().getName() + ",靜態同步方法0,運行結束");  
 }  
  
 // 重點:synchronized 修飾的方法,屬於方法鎖,鎖對象為(this)對象。  
 private synchronized void method1() {  
  System.out.println("線程名:" + Thread.currentThread().getName() + ",非靜態同步方法1,運行開始");  
  try {  
   Thread.sleep(4000);  
  } catch (InterruptedException e) {  
   e.printStackTrace();  
  }  
  System.out.println("線程:" + Thread.currentThread().getName() + ",非靜態同步方法1,運行結束");  
 }  
  
 //運行結果:並行  
 public static void main(String[] args) {  
  //問題原因: 線程1的鎖是類鎖(*.class)對象,線程2的鎖是方法鎖(this)對象,兩個線程的鎖不一樣,自然不會互相影響,所以會並行執行。  
  Thread thread1 = new Thread(instance);  
  Thread thread2 = new Thread(instance);  
  thread1.start();  
  thread2.start();  
  while (thread1.isAlive() || thread2.isAlive()) {  
  }  
  System.out.println("測試結束");  
 }  
 

運行結果:
線程名:Thread-0,靜態同步方法0,運行開始  
線程名:Thread-1,非靜態同步方法1,運行開始  
線程:Thread-1,非靜態同步方法1,運行結束  
線程:Thread-0,靜態同步方法0,運行結束  
測試結束  
 

場景八:同步方法拋出異常後,JVM會自動釋放鎖的情況

本場景探討的是synchronized釋放鎖的場景:

「只有當同步方法執行完或執行時拋出異常這兩種情況,才會釋放鎖。」

所以,在一個線程的同步方法中出現異常的時候,會釋放鎖,另一個線程得到鎖,繼續執行。而不會出現一個線程拋出異常後,另一個線程一直等待獲取鎖的情況。這是因為JVM在同步方法拋出異常的時候,會自動釋放鎖對象。

代碼實現:
public class Condition7 implements Runnable {  
  
 private static Condition7 instance = new Condition7();  
  
 @Override  
 public void run() {  
  if (Thread.currentThread().getName().equals("Thread-0")) {  
   //線程0,執行拋異常方法method0()  
   method0();  
  }  
  if (Thread.currentThread().getName().equals("Thread-1")) {  
   //線程1,執行正常方法method1()  
   method1();  
  }  
 }  
  
 private synchronized void method0() {  
  System.out.println("線程名:" + Thread.currentThread().getName() + ",運行開始");  
  try {  
   Thread.sleep(4000);  
  } catch (InterruptedException e) {  
   e.printStackTrace();  
  }  
  //同步方法中,當拋出異常時,JVM會自動釋放鎖,不需要手動釋放,其他線程即可獲取到該鎖  
  System.out.println("線程名:" + Thread.currentThread().getName() + ",拋出異常,釋放鎖");  
  throw new RuntimeException();  
  
 }  
  
 private synchronized void method1() {  
  System.out.println("線程名:" + Thread.currentThread().getName() + ",運行開始");  
  try {  
   Thread.sleep(4000);  
  } catch (InterruptedException e) {  
   e.printStackTrace();  
  }  
  System.out.println("線程:" + Thread.currentThread().getName() + ",運行結束");  
 }  
  
 public static void main(String[] args) {  
  Thread thread1 = new Thread(instance);  
  Thread thread2 = new Thread(instance);  
  thread1.start();  
  thread2.start();  
  while (thread1.isAlive() || thread2.isAlive()) {  
  }  
  System.out.println("測試結束");  
 }  
  
}  
 

運行結果:
線程名:Thread-0,運行開始  
線程名:Thread-0,拋出異常,釋放鎖  
線程名:Thread-1,運行開始  
Exception in thread "Thread-0" java.lang.RuntimeException  
 at com.study.synchronize.conditions.Condition7.method0(Condition7.java:34)  
 at com.study.synchronize.conditions.Condition7.run(Condition7.java:17)  
 at java.lang.Thread.run(Thread.java:748)  
線程:Thread-1,運行結束  
測試結束  
 

結果分析:

可以看出線程還是串行執行的,說明是線程安全的。而且出現異常後,不會造成死鎖現象,JVM會自動釋放出現異常線程的鎖對象,其他線程獲取鎖繼續執行。

總結

本文總結了並用代碼實現和驗證了synchronized各種使用場景,以及各種場景發生的原因和結論。我們分析的理論基礎都是synchronized關鍵字的鎖對象究竟是誰?多個線程之間競爭的是否是同一把鎖?根據這個條件來判斷線程是否是安全的。所以,有了這些場景的分析鍛鍊後,我們在以後使用多線程編程時,也可以通過分析鎖對象的方式,判斷出線程是否是安全的,從而避免此類問題的出現。

本文涵蓋了synchronized關鍵字的最重要的各種使用場景,也是面試官常常會問到的高頻問題,是一篇值得大家仔細閱讀和親自動手實踐的文章,喜歡本文請點讚和收藏。

來源:blog.csdn.net/x541211190/article/details/106272922


相關焦點

  • 掌握這 8 個Synchronized 用法,你就厲害了!
    作者|Albenalbenw.github.io/posts/854fc091/B 站搜索:楠哥教你學Java獲取更多優質視頻教程簡介本文將介紹8種同步方法的訪問場景,我們來看看這8種情況下,多線程訪問同步方法是否還是線程安全的。
  • Java synchronized 詳解
    • 了解JDK1.6對synchronized的具體優化內容,對於我們優化自己的並發代碼有很好的借鑑作用。• 能夠幫助我們更好的理解並發編程機制,有助我們在不同的情況下選擇更優的並發策略來完成任務。• 有助於我們學習Java中其他的鎖相關的內容。概要下面先簡單介紹一下本文的結構:1.用法介紹:簡單介紹synchronized的基本用法。
  • Java開發中synchronized的定義及用法
    synchronizedsynchronized是java中用於同步的關鍵字,其典型的作用域如下所示.用於保證test1函數中的被synchronized大括號包裹的代碼同步執行.synchronized作用的對象為SynchronizedExample1的對象實例,例如main函數中的example1以及example2.
  • 大話Synchronized及鎖升級
    使用方法從語法上講,Synchronized總共有三種用法:修飾實例方法public synchronized void eat(){    ..  ..}修飾靜態方法public static synchronized void eat(){    ..  ..
  • Java多線程synchronized
    在Java中,提供了兩種方式來實現同步互斥訪問:synchronized和Lock。本文主要講述synchronized的使用方法,Lock的使用方法在下一篇博文中講述。synchronized同步方法synchronized是Java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。
  • JAVA中synchronized與static synchronized 的區別
    那麼static synchronized恰好就是要控制類的所有實例的訪問了,static synchronized是限制線程同時訪問jvm中該類的所有實例同時訪問對應的代碼快。實際上,在類中某方法或某代碼塊中有 synchronized,那麼在生成一個該類實例後,改類也就有一個監視快,放置線程並發訪問改實例synchronized保護快,而static synchronized則是所有該類的實例公用一個監視快了,也也就是兩個的區別了,也就是synchronized相當於 this.synchronized,而static synchronized相當於Something.synchronized
  • 再有人問你synchronized是什麼,就把這篇文章發給他.
    對於程式設計師來說,synchronized只是個關鍵字而已,用起來很簡單。之所以我們可以在處理多線程問題時可以不用考慮太多,就是因為這個關鍵字幫我們屏蔽了很多細節。那麼,本文就圍繞synchronized展開,主要介紹其用法、原理,以及如何提供原子性、可見性和有序性保障的等。synchronized是Java提供的一個並發控制的關鍵字。
  • Java之戳中痛點之 synchronized 深度解析
    2、☞ 《Java面試手冊》.PDF    點擊查看作者:Json_wangqiangcnblogs.com/JsonShare/p/11433302.html概覽:簡介:作用、地位、不控制並發的影響用法:對象鎖和類鎖多線程訪問同步方法的7種情況性質:可重入、不可中斷
  • Java之戳中痛點之 synchronized 深度解析|java|override|author|...
    多線程訪問同步方法的7種情況    性質:可重入、不可中斷    原理:加解鎖原理、可重入原理、可見性原理    缺陷:效率低、不夠靈活、無法預判是否成功獲取到鎖    如何選擇Lock或Synchronized    如何提高性能
  • 「從入門到放棄-Java」並發編程-鎖-synchronized
    synchronized是java提供的一種內置的鎖機制。通過synchronized關鍵字同步代碼塊。線程在進入同步代碼塊之前會自動獲得鎖,並在退出同步代碼塊時自動釋放鎖。內置鎖是一種互斥鎖。本文來深入學習下synchronized。
  • Synchronized 天天用,實現原理你懂嗎?
    Synchronized 關鍵字算是Java的元老級鎖了,一開始它撐起了Java的同步任務,其用法簡單粗暴容易上手。但是有些與它相關的知識點還是需要我們開發者去深入掌握的。比如,我們都知道通過 Synchronized 鎖來實現互斥功能,可以用在方法或者代碼塊上,那麼不同用法都是怎麼實現的,以及都經歷了了哪些優化等等問題都需要我們紮實的理解。1.基本用法通常我們可以把 Synchronized 用在一個方法或者代碼塊裡,方法又有普通方法或者靜態方法。
  • Java的synchronized的使用
    Java的synchronized的使用Java中的額synchronized關鍵字,大家應該都很熟悉了,多線程中確保線程安全。Java中每個對象都可以作為鎖。對於靜態同步方法,鎖的是當前類的Clas3、對於同步方法塊,鎖的是synchronized裡面的對象。
  • Java並發編程:synchronized
    基本上所有的併發模式在解決線程安全問題時,都採用「序列化訪問臨界資源」的方案,即在同一時刻,只能有一個線程訪問臨界資源,也稱作同步互斥訪問。通常來說,是在訪問臨界資源的代碼前面加上一個鎖,當訪問完臨界資源後釋放鎖,讓其他線程繼續訪問。在Java中,提供了兩種方式來實現同步互斥訪問:synchronized和Lock。本文主
  • Java多線程:由淺入深看synchronized的底層實現原理
    淺聊synchronized的使用MDove:說起synchronized的底層實現原來,咱們先看看synchronized的倆種加鎖方式:1、某個對象實例內此作用域內的synchronized鎖 ,可以防止多個線程同時訪問這個對象的
  • 曉龍吊打面試官系列:synchronized關鍵字入門(同步方法與同步代碼塊)
    文章目錄一、 線程安全問題二、synchronized簡介三、synchronized的用法四、對象鎖和類鎖
  • 17張圖帶你秒殺synchronized關鍵字
    對於第一種情況,編譯器會為其自動生成了一個 ACC_SYNCHRONIZED 關鍵字用來標識。在 JVM 進行方法調用時,當發現調用的方法被 ACC_SYNCHRONIZED 修飾,則會先嘗試獲得鎖。對於第二種情況,編譯時在代碼塊開始前生成對應的1個 monitorenter 指令,代表同步塊進入。2個 monitorexit 指令,代表同步塊退出。這兩種方法底層都需要一個 reference 類型的參數,指明要鎖定和解鎖的對象。
  • 面試專題 | 其實你一直不了解 Synchronized 原理
    本篇文章將對synchronized機製做個大致的介紹,包括用以承載鎖狀態的對象頭、鎖的幾種形式、各種形式鎖的加鎖和解鎖流程、什麼時候會發生鎖升級。需要注意的是本文旨在介紹背景和概念,在講述一些流程的時候,只提到了主要case,對於實現細節、運行時的不同分支都在後面的文章中詳細分析。本人看的JVM版本是jdk8u,具體版本號以及代碼可以在這裡看到。
  • Java關鍵字synchronized 作為悲觀鎖,到底鎖的是什麼?
    代碼邏輯是這樣的:我們寫 2 個 synchronized實例方法,讓 5 個線程隨機執行 2 個方法。代碼如下:只有一個實例對象的情況運行結果:這份代碼裡面有 5 個線程競爭一個 synchronizedTest 資源,所以只能串行跑,我們這裡用了 2 個方法,為了讓大家更清楚地明白鎖的是對象,而不是鎖對象裡面的某個方法。
  • Java開發教程:volatile變量的使用建議及錯誤用法
    volatile變量的使用建議及錯誤用法這樣只要任何一個線程調用了shutdown() , 其他線程在執行do Work時都可以立即感知到shutdown Requested變量的變化。這時使用volatile比synchronized要簡單得多, 同時使用synchronized還會影響系統的吞吐量。volatile變量的錯誤用法注意:單個volatile變量單獨的讀、寫操作具有原子性。但是對於類似於++, -, 邏輯非!這種複合操作,這些操作整體上不具有原子性。
  • JAVA 並發編程Synchronized鎖的是什麼?
    當某個線程調用該對象的synchronized方法或者訪問synchronized代碼塊時,這個線程便獲得了該對象的鎖,其他線程暫時無法訪問這個方法,只有等待這個方法執行完畢或者代碼塊執行完畢,這個線程才會釋放該對象的鎖,其他線程才能執行這個方法或者代碼塊。下面我們將創建兩個線程A,B來同時訪問一個對象:A從帳戶裡取錢,B從帳戶裡存錢。