Java?synchornized與ReentrantLock處理并發(fā)出現(xiàn)的錯誤
什么是并發(fā)錯誤
多個線程共享操作同一個對象的時候,線程體當中連續(xù)的多行操作未必能夠連續(xù)執(zhí)行 很可能操作只完成了一部分,時間片突然耗盡,此時,另一個線程搶到時間片,直接拿走并訪問了操作不完整的數(shù)據(jù)(操作不完整的數(shù)據(jù),從邏輯上講是錯誤數(shù)據(jù))。
并發(fā)錯誤是如何產(chǎn)生的
根本原因: 多個線程共享操作同一份數(shù)據(jù)
直接原因: 線程體當中連續(xù)的多行語句,未必能夠連續(xù)執(zhí)行,很可能操作只完成了一半 時間片突然耗盡。
此時另一個線程剛好搶到時間片,直接拿走了操作不完整的數(shù)據(jù) - 錯誤數(shù)據(jù)。
導火索: 時間片突然耗盡
演示并發(fā)錯誤
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;
}
}
我們看運行結果發(fā)現(xiàn)一個非常嚴重的問題

我們的代碼從來沒有寫過將梁朝偉賦值為女士,也沒有寫過將張曼玉賦值為女士我們的程序為什么會出現(xiàn)這樣的情況 ?
線程體當中連續(xù)的多行操作未必能夠連續(xù)執(zhí)行 假如我們將stu的名字賦值為梁朝偉,此時CPU時間片耗盡了,另一個打印的線程搶到時間片的情況下 就會將原來的正確的值改為錯誤的數(shù)據(jù) 從而產(chǎn)生并發(fā)錯誤。
如何解決并發(fā)錯誤
要想解決并發(fā)錯誤加鎖是必須的
使用synchornized解決并發(fā)錯誤
synchronize語法級別的加鎖 也叫? 互斥鎖=互斥標記=鎖標記=鎖旗標=監(jiān)視器= Monitor
synchornized修飾代碼塊
synchronized(臨界資源){
//需要連續(xù)執(zhí)行的操作
}
synchornized修飾整個方法
public synchronized void add(){
}
//等價于
public void add(){
synchronized(){
}
}
注意:即便synchronized加在方法上,其實還是對對象進行加鎖,而且鎖的是調用方法的那個對象Java世界里只有每個對象才有鎖標記,所以加鎖只能對對象加鎖。
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){//我們要對一組連續(xù)的操作加鎖 不要對所有操作加鎖
//我們去廁所 只是鎖一次上廁所的過程 不要一輩子死在廁所里
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ā)錯誤
java.util.concurrent.locks.ReentrantLock(jdk 5.0開始):java包的工具包的并發(fā)包的 可重入鎖
ReentrantLock :lock(加鎖) unlock(解鎖):放在finally{}中
ReentrantLock可以在構造方法中傳公平鎖和非公平鎖(公平與否針對第一個先來的線程而言)
公平鎖:new Reetrantlock(true);
- JDK6.0之前這個Lock的機制比synchronized效率高很多 JDK6.0開始
- 重新對synchronized修改了底層實現(xiàn),加入了一堆新的概念 (偏向鎖 輕量級鎖 鎖的自旋機制) 從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();//鎖 既是一個名詞 又是一個動詞
try{
//synchronized(stu){//我們要對一組連續(xù)的操作加鎖 不要對所有操作加鎖
//我們去廁所 只是鎖一次上廁所的過程 不要一輩子死在廁所里
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;
}
}

此時已經(jīng)解決了并發(fā)錯誤
到此這篇關于Java synchornized與ReentrantLock處理并發(fā)出現(xiàn)的錯誤的文章就介紹到這了,更多相關Java synchornized與ReentrantLock內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot整合Web開發(fā)之文件上傳與@ControllerAdvice
@ControllerAdvice注解是Spring3.2中新增的注解,學名是Controller增強器,作用是給Controller控制器添加統(tǒng)一的操作或處理。對于@ControllerAdvice,我們比較熟知的用法是結合@ExceptionHandler用于全局異常的處理,但其作用不止于此2022-08-08
Java如何將Excel數(shù)據(jù)導入到數(shù)據(jù)庫
這篇文章主要為大家詳細介紹了Java將Excel數(shù)據(jù)導入到數(shù)據(jù)庫的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-10-10
Java+mysql本地圖片上傳數(shù)據(jù)庫及下載示例
本篇文章主要介紹了Java+mysql本地圖片上傳數(shù)據(jù)庫及下載示例,具有一定的參加價值,有興趣的可以了解一下。2017-01-01

