Java?synchornized與ReentrantLock處理并發(fā)出現(xiàn)的錯(cuò)誤
什么是并發(fā)錯(cuò)誤
多個(gè)線程共享操作同一個(gè)對(duì)象的時(shí)候,線程體當(dāng)中連續(xù)的多行操作未必能夠連續(xù)執(zhí)行 很可能操作只完成了一部分,時(shí)間片突然耗盡,此時(shí),另一個(gè)線程搶到時(shí)間片,直接拿走并訪問(wèn)了操作不完整的數(shù)據(jù)(操作不完整的數(shù)據(jù),從邏輯上講是錯(cuò)誤數(shù)據(jù))。
并發(fā)錯(cuò)誤是如何產(chǎn)生的
根本原因: 多個(gè)線程共享操作同一份數(shù)據(jù)
直接原因: 線程體當(dāng)中連續(xù)的多行語(yǔ)句,未必能夠連續(xù)執(zhí)行,很可能操作只完成了一半 時(shí)間片突然耗盡。
此時(shí)另一個(gè)線程剛好搶到時(shí)間片,直接拿走了操作不完整的數(shù)據(jù) - 錯(cuò)誤數(shù)據(jù)。
導(dǎo)火索: 時(shí)間片突然耗盡
演示并發(fā)錯(cuò)誤
public class TestConcurrentError{ public static void main(String[] args){ Student stu = new Student("張朝偉","先生"); PrintThread pt = new PrintThread(stu); ChangeThread ct = new ChangeThread(stu); pt.start(); ct.start(); } } class PrintThread extends Thread{ Student stu; public PrintThread(Student stu){ this.stu = stu; } @Override public void run(){ while(true){ System.out.println(stu); } } } class ChangeThread extends Thread{ Student stu; public ChangeThread(Student stu){ this.stu = stu; } @Override public void run(){ boolean isOkay = true; while(true){ if(isOkay){ stu.name = "張曼玉"; stu.gender = "女士"; }else{ stu.name = "梁朝偉"; stu.gender = "先生"; } isOkay = !isOkay; } } } class Student{ String name; String gender;//性別 public Student(String name,String gender){ this.name = name; this.gender = gender; } @Override public String toString(){ return name + " : " + gender; } }
我們看運(yùn)行結(jié)果發(fā)現(xiàn)一個(gè)非常嚴(yán)重的問(wèn)題
我們的代碼從來(lái)沒(méi)有寫過(guò)將梁朝偉賦值為女士,也沒(méi)有寫過(guò)將張曼玉賦值為女士我們的程序?yàn)槭裁磿?huì)出現(xiàn)這樣的情況 ?
線程體當(dāng)中連續(xù)的多行操作未必能夠連續(xù)執(zhí)行 假如我們將stu的名字賦值為梁朝偉,此時(shí)CPU時(shí)間片耗盡了,另一個(gè)打印的線程搶到時(shí)間片的情況下 就會(huì)將原來(lái)的正確的值改為錯(cuò)誤的數(shù)據(jù) 從而產(chǎn)生并發(fā)錯(cuò)誤。
如何解決并發(fā)錯(cuò)誤
要想解決并發(fā)錯(cuò)誤加鎖是必須的
使用synchornized解決并發(fā)錯(cuò)誤
synchronize語(yǔ)法級(jí)別的加鎖 也叫? 互斥鎖=互斥標(biāo)記=鎖標(biāo)記=鎖旗標(biāo)=監(jiān)視器= Monitor
synchornized修飾代碼塊
synchronized(臨界資源){ //需要連續(xù)執(zhí)行的操作 }
synchornized修飾整個(gè)方法
public synchronized void add(){ } //等價(jià)于 public void add(){ synchronized(){ } }
注意:即便synchronized加在方法上,其實(shí)還是對(duì)對(duì)象進(jìn)行加鎖,而且鎖的是調(diào)用方法的那個(gè)對(duì)象Java世界里只有每個(gè)對(duì)象才有鎖標(biāo)記,所以加鎖只能對(duì)對(duì)象加鎖。
public class TestConcurrentError{ public static void main(String[] args){ Student stu = new Student("張朝偉","先生"); PrintThread pt = new PrintThread(stu); ChangeThread ct = new ChangeThread(stu); pt.start(); ct.start(); } } //1st.用于打印顯示數(shù)據(jù)的線程 class PrintThread extends Thread{ Student stu; public PrintThread(Student stu){ this.stu = stu; } @Override public void run(){ while(true){ synchronized(stu){//我們要對(duì)一組連續(xù)的操作加鎖 不要對(duì)所有操作加鎖 //我們?nèi)?只是鎖一次上廁所的過(guò)程 不要一輩子死在廁所里 System.out.println(stu); } } } } class ChangeThread extends Thread{ Student stu; public ChangeThread(Student stu){ this.stu = stu; } @Override public void run(){ boolean isOkay = true; while(true){ synchronized(stu){ if(isOkay){ stu.name = "張曼玉"; stu.gender = "女士"; }else{ stu.name = "梁朝偉"; stu.gender = "先生"; } isOkay = !isOkay; } } } } class Student{ String name; String gender; public Student(String name,String gender){ this.name = name; this.gender = gender; } @Override public String toString(){ return name + " : " + gender; } }
使用ReentrantLock解決并發(fā)錯(cuò)誤
java.util.concurrent.locks.ReentrantLock(jdk 5.0開始):java包的工具包的并發(fā)包的 可重入鎖
ReentrantLock :lock(加鎖) unlock(解鎖):放在finally{}中
ReentrantLock可以在構(gòu)造方法中傳公平鎖和非公平鎖(公平與否針對(duì)第一個(gè)先來(lái)的線程而言)
公平鎖:new Reetrantlock(true);
- JDK6.0之前這個(gè)Lock的機(jī)制比synchronized效率高很多 JDK6.0開始
- 重新對(duì)synchronized修改了底層實(shí)現(xiàn),加入了一堆新的概念 (偏向鎖 輕量級(jí)鎖 鎖的自旋機(jī)制) 從JDK6.0開始 synchronized 跟 Lock性能上不相上下
import java.util.concurrent.locks.*; public class TestConcurrentErrorWithLock{ public static void main(String[] args){ Lock lock = new ReentrantLock(); Student stu = new Student("張朝偉","先生"); PrintThread pt = new PrintThread(stu,lock); ChangeThread ct = new ChangeThread(stu,lock); pt.start(); ct.start(); } } //1st.用于打印顯示數(shù)據(jù)的線程 class PrintThread extends Thread{ Student stu; Lock lock; public PrintThread(Student stu,Lock lock){ this.stu = stu; this.lock = lock; } @Override public void run(){ while(true){ lock.lock();//鎖 既是一個(gè)名詞 又是一個(gè)動(dòng)詞 try{ //synchronized(stu){//我們要對(duì)一組連續(xù)的操作加鎖 不要對(duì)所有操作加鎖 //我們?nèi)?只是鎖一次上廁所的過(guò)程 不要一輩子死在廁所里 System.out.println(stu); //} }finally{ lock.unlock(); } } } } class ChangeThread extends Thread{ Student stu; Lock lock; public ChangeThread(Student stu,Lock lock){ this.stu = stu; this.lock = lock; } @Override public void run(){ boolean isOkay = true; while(true){ //synchronized(stu){ lock.lock(); try{ if(isOkay){ stu.name = "張曼玉"; stu.gender = "女士"; }else{ stu.name = "梁朝偉"; stu.gender = "先生"; } isOkay = !isOkay; }finally{ lock.unlock(); } //} } } } class Student{ String name; String gender;//性別 public Student(String name,String gender){ this.name = name; this.gender = gender; } @Override public String toString(){ return name + " : " + gender; } }
此時(shí)已經(jīng)解決了并發(fā)錯(cuò)誤
到此這篇關(guān)于Java synchornized與ReentrantLock處理并發(fā)出現(xiàn)的錯(cuò)誤的文章就介紹到這了,更多相關(guān)Java synchornized與ReentrantLock內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- java ReentrantLock條件鎖實(shí)現(xiàn)原理示例詳解
- 一文帶你掌握J(rèn)ava?ReentrantLock加解鎖原理
- 深入剖析Java ReentrantLock的源碼
- 圖解Java?ReentrantLock的條件變量Condition機(jī)制
- 詳解Java?ReentrantLock可重入,可打斷,鎖超時(shí)的實(shí)現(xiàn)原理
- java?ReentrantLock并發(fā)鎖使用詳解
- 圖解Java?ReentrantLock公平鎖和非公平鎖的實(shí)現(xiàn)
- java鎖機(jī)制ReentrantLock源碼實(shí)例分析
- Java?AQS中ReentrantLock條件鎖的使用
相關(guān)文章
SpringBoot整合Web開發(fā)之文件上傳與@ControllerAdvice
@ControllerAdvice注解是Spring3.2中新增的注解,學(xué)名是Controller增強(qiáng)器,作用是給Controller控制器添加統(tǒng)一的操作或處理。對(duì)于@ControllerAdvice,我們比較熟知的用法是結(jié)合@ExceptionHandler用于全局異常的處理,但其作用不止于此2022-08-08

Java如何將Excel數(shù)據(jù)導(dǎo)入到數(shù)據(jù)庫(kù)

Java+mysql本地圖片上傳數(shù)據(jù)庫(kù)及下載示例

java實(shí)現(xiàn)簡(jiǎn)單學(xué)生管理系統(tǒng)項(xiàng)目