1. 程式人生 > 實用技巧 >java - synchronized關鍵字

java - synchronized關鍵字

synchronized使用總結

java多執行緒同步處理經常會使用到synchronized關鍵字,之前對其使用場景有些模糊不清,故做一些整理。

一、使用synchronized修飾非靜態方法

1 public class Hello{
2 
3    public synchronized void sayHello(){
4     System.out.println("Hello world");
5   }
6 }

這種方式是對每一個Hello物件上鎖,第一個訪問該方法的執行緒A則持有當前Hello物件的鎖,執行緒B要訪問該物件的執行緒會被阻塞,直到執行緒A訪問結束釋放該物件的鎖執行緒B才能訪問。但是如果執行緒B訪問的是Hello的另外一個物件,則不會被阻塞,因為sayHello是一個非靜態方法。

二、使用synchronized修飾靜態方法

1 public class Hello{
2 
3    public synchronized static void sayHello(){
4     System.out.println("Hello world");
5   }
6 }

static關鍵字修飾的方法表示該方法是一個類方法,與類的物件無關,所以當執行緒A首先持有了sayHello的鎖後,執行緒B無論訪問Hello的那個物件都會阻塞。

三、使用synchronized同步塊

前面兩種方法雖然能實現同步,但是效率不是很高。假設Hello有兩個被synchronized修飾的方法。當執行緒A訪問sayHello()時會持有Hello物件的鎖,這時,如果執行緒B

去訪問sayBye()時會被阻塞,因為訪問syaBye()需要持有Hello物件的鎖。有時候可能sayHello()和syaBye()併發不會有影響,這樣做就會降低程式效率。

public class Hello {

    public synchronized void sayHello() {
        System.out.println("Hello world");
    }
    
    public synchronized void sayBye() {
        System.out.println("bye bye");
    }
}

所以java有了synchronized同步塊的使用,同步塊也可以分為兩種。靜態和非靜態。

非靜態同步塊:

public class Hello {

    private final Object lockHello = new Object();
    private final Object lockBye = new Object();
    public void sayHello(){
        synchronized (lockHello) {
            System.out.println("hello");
        }
    }
    public synchronized void sayBye() {
        synchronized (lockBye) {
            System.out.println("bye");
        }
 }
}

這樣當執行緒A訪問sayHello時就不會影響執行緒B訪問sayBye了。靜態和非靜態的區別與前面兩種是一樣的。

靜態同步塊:

public class Hello {

    private static final Object lock = new Object();
    public void sayHello(){
        synchronized (lock) {
            System.out.println("hello");
        }
    }
}