首頁 Java java教程 synchronized關鍵字的使用

synchronized關鍵字的使用

Sep 06, 2019 pm 04:02 PM
synchronized

synchronized關鍵字是java並發程式設計中常用的同步鎖,用來鎖住方法或程式碼區塊,鎖定程式碼區塊時可以是synchronized(this){}、synchronized(Object){}、synchronized(類別class) {}。

synchronized關鍵字的使用

當鎖定的內容執行完或執行過程中拋出異常,才會自動釋放鎖定。

如果想要手動釋放鎖,需要呼叫鎖定的物件的wait()方法釋放掉鎖定並且置於等待狀態,切換到其他執行緒運行,而notify()方法只是喚醒一個呼叫了該對象wait()方法的其他線程,但不會釋放鎖,選擇順序也不由程式碼控制,由虛擬機器實作。

因此,物件的wait()、notify()、notifyAll()方法只能是配合synchronized關鍵字使用的,來完成執行緒間的調度。

其中鎖定方法等同於synchronized(this){方法的所有程式碼作為程式碼區塊},如下:

public synchronized void test() {
...
}
登入後複製

等同於

public void test() {
synchronized (this) {
...
}
}
登入後複製

上面的範例鎖住的是該類別的對象,如果鎖住的是個靜態的方法,我們知道靜態方法是屬於類別的而不屬於對象的,所以,synchronized修飾的靜態方法鎖定的是這個類別的所有對象,即就算是兩個實例對象,只要他們都是這個類的,那都會鎖住。

public synchronized static void test() {
	...
}
登入後複製

等同於

public static void test() {
synchronized (所在类.class) {
...
}	
}
登入後複製

無論是鎖定方法還是鎖定程式碼區塊,無論鎖定程式碼區塊時的參考物件是什麼,只要記住一個原則就一目了然了,那就是當參考對象相同時,同步鎖才起作用,否則鎖不會互斥,可以並發執行。

synchronized(this)表示當前類別的物件實例相同時鎖起作用,synchronized(Object)表示該Object物件相同時鎖起作用,synchronized(類別class)表示當都是該class類別時鎖起作用。

舉一個簡單的例子:

public class TestController {
 
    public class Task implements Runnable{
		private String str;
		
		Task(String str){
			this.str=str;
		}
		
		@Override
		public void run() {
			synchronized (str) {
				try {
					Thread.sleep(3000l);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(str);
			}
		}
		
	}
	
	public static void main(String[] args) throws InterruptedException {
		TestController testController = new TestController();
		Thread thread1 = new Thread(testController.new Task("1"));
		Thread thread2 = new Thread(testController.new Task("1"));
		thread1.start();
		thread2.start();
	}
}
登入後複製

上述程式碼,參考物件str都是"1",在java中,String字串如果透過this.str="1"這樣的方式賦值就等於str=String.valueOf("1"),如果字串"1"之前已經初始化過,那就會直接拿之前的,所以是同一個物件。根據上面介紹的原則,那鎖就會起作用,所以結果是3秒之後輸出1,再過3秒再輸出1。

如果把thread2改成

Thread thread2 = new Thread(testController.new Task("2"));
登入後複製

這時參考對像一個是"1",另一個是"2",不是同一個對象,所以鎖不會互斥,就不會起作用,所以結果是3秒後幾乎同時輸出1和2。

以上都是多個執行緒同時呼叫同一個方法,如果呼叫不同的方法呢?

public class Test{
	
	public synchronized void m1(){
		System.out.println("m1 running...");
		try {
			Thread.sleep(3000l);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("m1 end");
	}
	
	public synchronized void m2(){
		System.out.println("m2 running...");
		System.out.println("m2 end");
	}
	
	public static void main(String[] args) {
		Test test = new Test();
		new Thread(new Runnable() {
			@Override
			public void run() {
				test.m1();
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				test.m2();
			}
		}).start();
	}
	
}
登入後複製

上面程式碼的輸出結果是:

m1 running...
//过3秒
m1 end
m2 running...
m2 end
登入後複製

上面就說過synchronized修飾在方法上等同於synchronized(this){方法的所有程式碼作為程式碼區塊},而this就代表是對象,也就是說,第一個Thread得到的是test物件的鎖,因為物件都是同一個test,所以第二個Thread無法取得到鎖,而被阻塞。

把上面的範例改造成如下:

private String str = "1";
	
public void m1(){
	synchronized(str){
		System.out.println("m1 running...");
		try {
			Thread.sleep(3000l);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("m1 end");
	}
}
 
public void m2(){
	synchronized(str){
		System.out.println("m2 running...");
		System.out.println("m2 end");
	}
}
登入後複製

第一個Thread呼叫m1()時取得到的是物件str的鎖,第二個Thread呼叫m2()時也需要取得對象str的鎖,而且因為是同一個Test對象,所以兩個str也是同一個對象,所以第二個Thread會因為取得不到鎖而被阻塞,輸出結果和之前的例子一樣。

如果再把上面的例子改造成如下:

public class M1 {
	
	public void m(String str){
		synchronized (str) {
			System.out.println("m1 runing");
			try {
				Thread.sleep(3000l);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("m1 end");
		}
	}
 
}
public class M2 {
	
	public void m(String str){
		synchronized (str) {
			System.out.println("m2 runing");
			System.out.println("m2 end");
		}
	}
 
}
public class Test {
 
	public static void main(String[] args) {
		String str = "1";
		new Thread(new Runnable() {
			@Override
			public void run() {
				new M1().m(str);
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				new M2().m(str);
			}
		}).start();
	}
	
}
登入後複製

這次呼叫的方法在兩個類別裡面,但是結果和之前的兩個例子是一樣的,因為鎖住的都是傳進來的str對象,同一個對像只有一把鎖,第一個Thread拿了,第二個Thread就只能等待。

總結:

A. 無論synchronized關鍵字加在方法上還是物件上,如果它作用的物件是非靜態的,則它取得的鎖定是對象;如果synchronized作用的物件是一個靜態方法或一個類,則它所取得的鎖是對類,該類所有的物件同一把鎖。 

B. 每個物件只有一個鎖定(lock)與之相關聯,誰拿到這個鎖誰就可以執行它所控制的那段程式碼。 

C. 實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制

以上是synchronized關鍵字的使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Java中Synchronized的原理與使用場景及Callable介面的使用方法及區別分析 Java中Synchronized的原理與使用場景及Callable介面的使用方法及區別分析 Apr 21, 2023 am 08:04 AM

一、基本特性1.一開始是樂觀鎖,如果鎖衝突頻繁,就轉換為悲觀鎖.2.開始是輕量級鎖實現,如果鎖被持有的時間較長,就轉換成重量級鎖. 3.實現輕量級鎖的時候大概率用到的自旋鎖策略4.是一種不公平鎖5.是一種可重入鎖6.不是讀寫鎖二、加鎖工作過程JVM將synchronized鎖分為無鎖、偏向鎖、輕量級鎖、重量級鎖狀態。會根據情況,進行依序升級。偏向鎖假設男主角是一個鎖,女主角是一個線程.如果只有這一個線程來使用這個鎖,那麼男主女主即使不領證結婚(避免了高成本操作),也可以一直幸福的生活下去.但是女配出現

Java關鍵字synchronized原理與鎖定的狀態實例分析 Java關鍵字synchronized原理與鎖定的狀態實例分析 May 11, 2023 pm 03:25 PM

一、Java中鎖的概念自旋鎖:是指當一個線程獲取鎖的時候,如果鎖已經被其它線程獲取,那麼該線程將循環等待,然後不斷的判斷鎖是否能被成功獲取,直到獲取到鎖才會退出循環。樂觀鎖:假定沒有衝突,在修改數據時如果發現數據和先前取得的不一致,則讀最新數據,重試修改。悲觀鎖:假定會發生並發衝突,同步所有對資料的相關操作,從讀取資料就開始上鎖。獨享鎖(寫):給資源加上寫鎖,執行緒可以修改資源,其它執行緒不能再加鎖(單一寫)。共享鎖(讀):給資源加上讀鎖後只能讀不能修改,其它執行緒也只能加讀鎖,不能加寫鎖(多度)。看成S

Java中如何利用synchronized實作同步機制? Java中如何利用synchronized實作同步機制? Apr 22, 2023 pm 02:46 PM

Java的synchronized使用方法總結1.把synchronized當作函數修飾符時,範例程式碼如下:Publicsynchronizedvoidmethod(){//….}這也就是同步方法,那這時synchronized鎖定的是哪個物件呢?他鎖定的是呼叫這個同步方法物件。也就是說,當一個物件P1在不同的執行緒中執行這個同步方法時,他們之間會形成互斥,達到同步的效果。但是這個物件所屬的Class所產生的另一物件P2卻能夠任意呼叫這個被加了synchronized關鍵字的方法。上邊的範例程式碼等

Java中的三種同步方式和它們的使用方法是什麼? Java中的三種同步方式和它們的使用方法是什麼? Apr 27, 2023 am 09:34 AM

1.說明synchronized算是我們最常用的同步方式,主要有三種使用方式。 2.實例//普通類別方法同步synchronizedpublidvoidinvoke(){}//類別靜態方法同步synchronizedpublicstaticvoidinvoke(){}//程式碼區塊同步synchronized(object){}這三種方式的不同之處在於同步的物件不同,普通類別synchronized同步的是物件本身,靜態方法同步的是類別Class本身,程式碼區塊同步的是我們在括號內部填入的物件。 Java有哪些集合

Java Synchronized鎖定升級原理及流程是什麼 Java Synchronized鎖定升級原理及流程是什麼 Apr 19, 2023 pm 10:22 PM

工具準備在正式談synchronized的原理之前我們先談一下自旋鎖,因為在synchronized的優化當中自旋鎖發揮了很大的作用。而需要了解自旋鎖,我們首先要了解什麼是原子性。所謂原子性簡單說來就是一個一個操作要么不做要么全做,全做的意思就是在操作的過程當中不能夠被中斷,比如說對變量data進行加一操作,有以下三個步驟:將data從記憶體載入到暫存器。將data這個值加一。將得到的結果寫回記憶體。原子性就表示一個執行緒在進行加一操作的時候,不能夠被其他執行緒中斷,只有這個執行緒執行完這三個過程的時候

Java中為什麼需要提供Lock,而不只使用synchronized關鍵字? Java中為什麼需要提供Lock,而不只使用synchronized關鍵字? Apr 20, 2023 pm 05:01 PM

摘要:在Java中提供了synchronized關鍵字來保證只有一個執行緒能夠存取同步程式碼區塊。既然已經提供了synchronized關鍵字,為何在Java的SDK包中,還會提供Lock介面呢?這是不是重複造輪子,多此一舉呢?今天,我們就一起來探討下這個問題。在Java中提供了synchronized關鍵字來保證只有一個執行緒能夠存取同步程式碼區塊。既然已經提供了synchronized關鍵字,為何在Java的SDK包中,還會提供Lock介面呢?這是不是重複造輪子,多此一舉呢?今天,我們就一起來探討下

Java Synchronized是什麼 Java Synchronized是什麼 May 14, 2023 am 08:28 AM

Synchronized是什麼各位Java讀者,對於synchronized關鍵字並不陌生,在各種中間件源碼或JDK源碼中都能看到,對於不熟悉synchronized的讀者只知道在多線程中需要使用到synchronized關鍵字,知道synchronized能夠保證線程安全。稱之為:互斥鎖(同時只能一個執行緒執行,其他的執行緒將會等待)又稱之為:悲觀鎖(同時只能一個執行緒執行,其他的執行緒將會等待)JVM虛擬機幫你實現,開發者只需要使用synchronized關鍵字即可。使用時需要用一個物件當鎖的互斥

Java中有多少個非存取修飾符? Java中有多少個非存取修飾符? Aug 30, 2023 pm 06:01 PM

Java提供了一些其他修飾符來提供除可見性之外的功能。這些修飾符稱為非存取修飾符靜態宣告為靜態的成員對於類別的所有實例都是通用的。靜態成員是儲存在類別記憶體中的類別層級成員。 Final此修飾符用於限制變數、方法或類別的進一步修改。宣告為final的變數的值一旦獲得值就不能修改。 Final方法不能在子類別中重寫,也不能建立Final類別的子類別。抽象此修飾符可以與類別或方法一起使用。您不能將此修飾符應用於變數和建構函式。聲明為抽象的方法必須在子類別中進行修改。您無法實例化聲明為抽象的類別。同步此修飾符用於控制多個執行緒

See all articles