首頁  >  文章  >  Java  >  Java如何利用Synchronized實現多執行緒同步

Java如何利用Synchronized實現多執行緒同步

PHPz
PHPz轉載
2023-04-30 16:19:07994瀏覽

使用同步的原因

1. 在系統中對訪類別要使用多執行緒進行存取;

2. 在該類別中有類別變量, 或是在類別的方法中有存取公共資源(如一個外部文件的讀寫)。

同步鎖定鎖定的內容是什麼?

無論你將Synchronized加在方法前還是加在一個變數前,其鎖定的都是一個 類別物件。每一個物件都只有一個鎖與之相關聯。

下例中分情況的列舉各種情況下的同步效果

1. Synchronized 加在方法上, (同步方法,鎖定類別實例)

Java程式碼

public class Demo1 {             public synchronized void m1(){             //...............         }             public void m2(){             //............                 synchronized(this){                 //.........             }                 //........         }     }

這兩種寫法的效果是一樣的,鎖定的都是類別實例物件。如果有一個類別實例物件: demo = new Demo1(),另外有兩個線程: thread1,thread2,都調用了demo 對象,那麼,在同一時間,如果thread1調用了demo.m1(),則thread2在該時間內不能存取demo.m1() 和demo.m2(); 因為thread1把demo這個物件的鎖定使用了,所以無法分給其它執行緒使用

但是,如果thread1呼叫demo1.m1() , thread2呼叫demo2.m1(), 則可以同時進行,因為它們呼叫的是不同的Demo1類別物件實例。

2. Synchronized 加在變數上, (同步區塊,鎖定類別實例)

Java程式碼

public class Demo2 {         Object a = new Object();         Object b = new Object();             public void m1(){             //............                 synchronized(a){                 //.........             }                 //........         }             public void m2(){             //............                 synchronized(b){                 //.........             }                 //........         }     }

在這種情況下,是實現程式碼區塊鎖定,鎖定的物件是變數a 或b; (注意,a 、b 都是非static 的)如果有一個類別實例物件: demo = new Demo2(),另外有兩個執行緒:thread1,thread2,都調用了demo 對象,那麼,在同一時間,如果thread1調用了demo.m1(),則thread2在該時間內可以訪問demo.m2();但不能訪問demo.m1() 的同步塊,因為a被thread1鎖定了。

3. Synchronized 鎖定的是類別變量,即static 變數(可能是屬性,可能是方法)(鎖定類別物件)

Java程式碼

##
public class Demo3 {         static Object o = new Object();             public static synchronized void m1() {             //....         }             public static void m2() {             //...             synchronized (Demo3.class) {                 //.....             }             //.....         }             public static void m3() {             //..........             try {                 synchronized (Class.forName("Demo3")) {                   //............                 }             } catch (ClassNotFoundException ex) {             }             //.............         }             public static void m4() {             //............            synchronized(o){              //........            }             //..........         }     }
以上4個方法中實現的效果都是一樣的,其鎖定的對像都是類Demo3,而不是類實例對象,即在多線程中,其共享的資源是屬於類的,而不是屬於類對象的。在這種情況下,如果thread1 存取了這4個方法中的任何一個, 在同一時間內其它的執行緒都不能存取 這4個方法。

4. 在類別的方法中存取了多執行緒共同的資源, 且該資源是可變的,這種情況下也是需要進行同步的

Java程式碼

#
public class Demo4 {         static String path = "file path";             public void readConfiFile() {             synchronized (path) {                // 读取该path指定的文件。             }             }             public void writeConfiFile() {             synchronized (path) {                 //写信息到该path指定的文件。             }         }     }
這種情況下,必須鎖定為類別變量,而不能進行鎖定類別實例對象,因為這是變象的一種類別資源共享,而不是類別實例對象資源共享。

線程,成也其,敗也其,用好了可以提升性能,用不好則會使系統後患無窮。

PS: 進行執行緒同步需要很大的系統開銷, 所以,在使用時,如果不是必須的,則盡量不使用同步功能。

以上是Java如何利用Synchronized實現多執行緒同步的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除