Java?Synchronized鎖的使用詳解
Synchronized的用法
在多線程并發(fā)問題中,常用Synchronized鎖解決問題。Synchronized鎖通常用于同步示例方法,同步靜態(tài)方法,同步代碼塊等。
同步示例方法
我們可能自己使用過在方法前加Synchronized鎖修飾,在多線程并發(fā)同時(shí)調(diào)用同一個(gè)實(shí)例化對(duì)象時(shí),如果這個(gè)方法加上了Synchronized鎖,那么也是線程安全的。
舉個(gè)栗子:
package Thread;
import java.util.stream.IntStream;
public class ThreadTest {
private Long count=0L;
public void incrementCount(){
count++;
}
public Long execute() throws InterruptedException {
Thread thread1=new Thread(()->{
IntStream.range(0,1000).forEach((i)->incrementCount());//線程1循環(huán)1000次
});
Thread thread2=new Thread(()->{
IntStream.range(0,1000).forEach((i)->incrementCount());//線程2循環(huán)1000次
});
thread1.start();//開啟線程
thread2.start();
thread1.join();//等待線程1和線程2執(zhí)行完畢
thread2.join();
return count;
}
public static void main(String[] args) throws InterruptedException {
ThreadTest threadTest=new ThreadTest();
Long count = threadTest.execute();
System.out.println(count);
}
}
在上面的程序中,count變量為成員變量,在多線程同時(shí)使用時(shí)極大可能會(huì)發(fā)生錯(cuò)誤,在前面也講到過count++包含三個(gè)步驟:1.將變量count從主內(nèi)存中加載到CPU的寄存器中;2.在CPU的寄存器中執(zhí)行count++或++count的操作;3.將運(yùn)算的count++的結(jié)果寫入緩存或內(nèi)存中。兩個(gè)線程都會(huì)更新count的值到內(nèi)存中,當(dāng)其中一個(gè)線程再從內(nèi)存中讀取數(shù)據(jù)時(shí),可能讀到的成員變量會(huì)與當(dāng)前的變量不一致,從而使得最終count的結(jié)果不為2000,因此會(huì)發(fā)生錯(cuò)誤。
如何能解決這種錯(cuò)誤?就是為incrementCount方法加鎖:
public synchronized void incrementCount(){
count++;
}
這樣就能保證所得到的count最終值為2000了。
同步靜態(tài)方法
當(dāng)一個(gè)類的某個(gè)靜態(tài)方法加了synchronized鎖時(shí),就相當(dāng)于給這個(gè)類的class對(duì)象加鎖。所以無論創(chuàng)建多少個(gè)當(dāng)前類的對(duì)象調(diào)用這個(gè)被synchronized鎖修飾的靜態(tài)方法時(shí),都是線程安全的。
如上面的例子,修改如下:
package Thread;
import java.util.stream.IntStream;
public class ThreadTest {
private static Long count=0L;
public static synchronized void incrementCount(){
count++;
}
public static Long execute() throws InterruptedException {
Thread thread1=new Thread(()->{
IntStream.range(0,1000).forEach((i)->incrementCount());
});
Thread thread2=new Thread(()->{
IntStream.range(0,1000).forEach((i)->incrementCount());
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
return count;
}
public static void main(String[] args) throws InterruptedException {
ThreadTest threadTest=new ThreadTest();
Long count = threadTest.execute();
System.out.println(count);
}
}
因此,當(dāng)多個(gè)線程并發(fā)執(zhí)行調(diào)用被synchronized鎖修飾的靜態(tài)方法時(shí),這個(gè)靜態(tài)方法是線程安全的。
同步代碼塊
前面提到加了synchronized鎖的方法在多線程并發(fā)條件下是線程安全的,但是在執(zhí)行業(yè)務(wù)邏輯過多的代碼塊時(shí),可能會(huì)影響程序的執(zhí)行效率。對(duì)于此時(shí),可以把一個(gè)方法分成多個(gè)小的臨界區(qū)。
舉個(gè)栗子:
private Long count1=0L;
private Long count2=0L;
public synchronized void incrementCount(){
count1++;
count2++;
}
在上面的代碼中,count1和count2為兩個(gè)不同的自增操作,因此對(duì)于count1和count2來說是兩個(gè)不同的臨界區(qū)資源。當(dāng)一個(gè)線程進(jìn)入incrementCount方法中時(shí),會(huì)對(duì)整個(gè)方法進(jìn)行加鎖,在對(duì)count1進(jìn)行自增操作時(shí),也會(huì)占用count2的資源,相當(dāng)于占用全部的資源。只有等到這個(gè)線程執(zhí)行完count1++和count2++的操作時(shí),釋放鎖時(shí),其它線程才能拿到鎖資源進(jìn)入incrementCount方法。
但是這樣會(huì)影響程序的性能。因?yàn)閏ount1++和count2++為兩個(gè)互不影響的兩個(gè)臨界區(qū)資源,當(dāng)線程拿到鎖,會(huì)占用兩個(gè)資源,使得臨界區(qū)資源進(jìn)行閑置等待,因此可以優(yōu)化代碼,讓synchronized鎖修飾代碼塊。
修改后的代碼:
private Long count1=0L;
private Long count2=0L;
public Object count1Lock=new Object();
public Object count2Lock=new Object();
public void incrementCount(){
synchronized (count1Lock){
count1++;
}
synchronized (count2Lock){
count2++;
}
}
上面代碼中,對(duì)count1和count2分別建立了對(duì)象鎖count1Lock和count2Lock,而沒有對(duì)incrementCount加鎖,意為當(dāng)一個(gè)線程進(jìn)入incrementCount方法時(shí),其他線程也能進(jìn)入此方法,當(dāng)線程1拿到count1Lock對(duì)象鎖時(shí),不影響線程2拿到count2Lock對(duì)象鎖來對(duì)count2執(zhí)行自增操作。
這樣既提高了程序的執(zhí)行效率,同時(shí),由于臨界區(qū)資源都加了鎖,incrementCount方法也是線程安全的。
到此這篇關(guān)于Java Synchronized鎖的使用詳解的文章就介紹到這了,更多相關(guān)Java Synchronized鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java同步鎖Synchronized底層源碼和原理剖析(推薦)
- java同步鎖的正確使用方法(必看篇)
- 95%的Java程序員人都用不好Synchronized詳解
- Java?synchronized同步關(guān)鍵字工作原理
- Java synchronized偏向鎖的概念與使用
- Java?synchronized輕量級(jí)鎖實(shí)現(xiàn)過程淺析
- Java synchronized重量級(jí)鎖實(shí)現(xiàn)過程淺析
- Java @Transactional與synchronized使用的問題
- Java?synchronized與死鎖深入探究
- Java synchronized與CAS使用方式詳解
- 淺析Java關(guān)鍵詞synchronized的使用
- synchronized及JUC顯式locks?使用原理解析
- java鎖synchronized面試常問總結(jié)
- Java?HashTable與Collections.synchronizedMap源碼深入解析
- AQS加鎖機(jī)制Synchronized相似點(diǎn)詳解
- Java必會(huì)的Synchronized底層原理剖析
- 一個(gè)例子帶你看懂Java中synchronized關(guān)鍵字到底怎么用
- 詳解Java?Synchronized的實(shí)現(xiàn)原理
- Synchronized?和?ReentrantLock?的實(shí)現(xiàn)原理及區(qū)別
- Java同步鎖synchronized用法的最全總結(jié)
相關(guān)文章
Java使用Poi導(dǎo)出Excel表格方法實(shí)例
這篇文章主要給大家介紹了關(guān)于Java使用Poi導(dǎo)出Excel表格的相關(guān)資料,Java POI是一個(gè)用于操作Microsoft Office格式的Java API庫,可以使用它來導(dǎo)出Excel文件,需要的朋友可以參考下2023-10-10
如何在 Spring Boot 中配置和使用 CSRF 保護(hù)
CSRF是一種網(wǎng)絡(luò)攻擊,它利用已認(rèn)證用戶的身份來執(zhí)行未經(jīng)用戶同意的操作,Spring Boot 提供了內(nèi)置的 CSRF 保護(hù)機(jī)制,可以幫助您防止這種類型的攻擊,這篇文章主要介紹了Spring?Boot?中的?CSRF?保護(hù)配置的使用方法,需要的朋友可以參考下2023-09-09
SpringMVC使用第三方組件實(shí)現(xiàn)文件上傳
這篇文章主要介紹了SpringMVC使用第三方組件實(shí)現(xiàn)文件上傳,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
Springboot?前后端分離項(xiàng)目使用?POI?生成并導(dǎo)出?Excel的操作方法
在做一個(gè)?SpringBoot?前后端分離項(xiàng)目的時(shí)候,需要將數(shù)據(jù)存到?Excel中,用戶可以下載?Excel,具體實(shí)現(xiàn)是采用?Apache?強(qiáng)大的?POI,本文給大家介紹Springboot?前后端分離項(xiàng)目使用?POI?生成并導(dǎo)出?Excel相關(guān)知識(shí),感興趣的朋友一起看看吧2023-09-09

