Java使用線程同步解決線程安全問題詳解
第一種方法:同步代碼塊:
作用:把出現(xiàn)線程安全的核心代碼上鎖
原理:每次只能一個線程進入,執(zhí)行完畢后自行解鎖,其他線程才能進來執(zhí)行
鎖對象要求:理論上,鎖對象只要對于當前同時執(zhí)行的線程是同一個對象即可
缺點:會干擾其他無關線程的執(zhí)行
所以,這種只是理論上的,了解即可,現(xiàn)實中并不會這樣用
public class 多線程_4線程同步 { public static void main(String[] args) { //定義線程類,創(chuàng)建一個共享的賬戶對象 account a=new account("abc",10000); //創(chuàng)建兩個取錢的線程對象 new drawthread(a,"小明").start(); new drawthread(a,"小紅").start(); } } //取錢的線程類 class drawthread extends Thread{ //接收處理的賬戶對象 private account acc; public drawthread(account acc,String name){ super(name); this.acc=acc; } public void run(){ //取錢 acc.drawmoney(10000); } } class account{ private String cartId; private double money;//賬戶余額 public account() { } public account(String cartId, double money) { this.cartId = cartId; this.money = money; } public String getCartId() { return cartId; } public void setCartId(String cartId) { this.cartId = cartId; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } public void drawmoney(double money) { //先獲取是誰來取錢,線程名即是人名 String name=Thread.currentThread().getName(); //同步代碼塊 //作用:把出現(xiàn)線程安全的核心代碼上鎖 //原理:每次只能一個線程進入,執(zhí)行完畢后自行解鎖,其他線程才能進來執(zhí)行 //鎖對象要求:理論上,鎖對象只要對于當前同時執(zhí)行的線程是同一個對象即可 //缺點:會干擾其他無關線程的執(zhí)行 synchronized ("遇安") {//"鎖名自取,無意義" //判斷賬戶是否夠錢 if(this.money>=money){ //取錢 System.out.println(name+"來取錢成功,取了:"+money); //更新金額 this.money-=money; System.out.println(name+"取錢后剩余:"+this.money); }else{ //余額不足 System.out.println(name+"來取錢,但余額不足!"); } } } }
規(guī)范上:建議使用共享資源作為鎖對象
對于實例化方法建議使用this作為鎖對象
對于靜態(tài)方法,建議使用字節(jié)碼(類名.class)對象作為鎖對象
//接上文代碼 //實例化方法建議使用this作為鎖對象 synchronized (this) { //判斷賬戶是否夠錢 if(this.money>=money){ //取錢 System.out.println(name+"來取錢成功,取了:"+money); //更新金額 this.money-=money; System.out.println(name+"取錢后剩余:"+this.money); }else{ //余額不足 System.out.println(name+"來取錢,但余額不足!"); } }
//靜態(tài)方法建議使用類名.class作為鎖對象 //每次只有一個線程能鎖這個類,而類也是唯一的 public static void run(){ synchronized(account.class){ } }
第二種方法:同步方法
//同步方法 public synchronized void drawmoney(double money) { //先獲取是誰來取錢,線程名即是人名 String name=Thread.currentThread().getName(); //判斷賬戶是否夠錢 if(this.money>=money){ //取錢 System.out.println(name+"來取錢成功,取了:"+money); //更新金額 this.money-=money; System.out.println(name+"取錢后剩余:"+this.money); }else{ //余額不足 System.out.println(name+"來取錢,但余額不足!"); } }
那么同步代碼塊和同步方法哪個好一點呢?
答案是:同步代碼塊
因為同步代碼塊鎖的范圍更小一點,同步方法鎖的范圍更大一點
但其實在現(xiàn)實中同步方法用的更多一點,因為代碼簡潔好寫一點,更方便
第三種方法:Lock鎖
JDK5后出現(xiàn),更加靈活方便
Lock是接口不能直接實例化,我們需要采用它的實現(xiàn)類ReentrantLock來構(gòu)建Lock鎖對象
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class 多線程_4線程同步Lock鎖 { public static void main(String[] args) { //定義線程類,創(chuàng)建一個共享的賬戶對象 account a=new account("abc",10000); //創(chuàng)建兩個取錢的線程對象 new drawthread(a,"小明").start(); new drawthread(a,"小紅").start(); } } //取錢的線程類 class drawthread2 extends Thread{ //接收處理的賬戶對象 private account acc; public drawthread2(account acc,String name){ super(name); this.acc=acc; } public void run(){ //取錢 acc.drawmoney(10000); } } class account2{ private String cartId; private double money;//賬戶余額 //final修飾后:鎖對象是唯一的和不可替換的 //Lock是接口不能直接實例化,我們需要采用它的實現(xiàn)類ReentrantLock來構(gòu)建Lock鎖對象 private final Lock lock=new ReentrantLock(); public account2() { } public account2(String cartId, double money) { this.cartId = cartId; this.money = money; } public String getCartId() { return cartId; } public void setCartId(String cartId) { this.cartId = cartId; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } public void drawmoney(double money) { //先獲取是誰來取錢,線程名即是人名 String name=Thread.currentThread().getName(); lock.lock();//上鎖 //判斷賬戶是否夠錢 try { if(this.money>=money){ //取錢 System.out.println(name+"來取錢成功,取了:"+money); //更新金額 this.money-=money; System.out.println(name+"取錢后剩余:"+this.money); }else{ //余額不足 System.out.println(name+"來取錢,但余額不足!"); } //防止代碼出現(xiàn)bug而不能解鎖 } finally { lock.unlock();//解鎖 } } }
到此這篇關于Java使用線程同步解決線程安全問題詳解的文章就介紹到這了,更多相關Java線程同步內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot3.2.2整合MyBatis Plus3.5.5的詳細過程
這篇文章給大家介紹了SpringBoot3.2.2整合MyBatis Plus3.5.5的詳細過程,文中通過代碼示例給大家介紹的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2024-01-01Java中的ConcurrentLinkedQueue松散隊列解析
這篇文章主要介紹了Java中的ConcurrentLinkedQueue松散隊列解析,鏈表是松散的,鏈表節(jié)點并不都是有效的,允許存在無效節(jié)點val=null,但是只有最后一個節(jié)點才能next=null,需要的朋友可以參考下2023-12-12idea快速搭建spring cloud注冊中心與注冊的方法
這篇文章主要介紹了idea快速搭建spring cloud注冊中心與注冊的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07IntelliJ IDEA設置Tabs實現(xiàn)同時打開多個文件且分行顯示
今天小編就為大家分享一篇關于IntelliJ IDEA設置Tabs實現(xiàn)同時打開多個文件且分行顯示,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-10-10Java創(chuàng)建對象(顯式創(chuàng)建和隱含創(chuàng)建)
本文詳細介紹對象的創(chuàng)建,在 Java 語言中創(chuàng)建對象分顯式創(chuàng)建與隱含創(chuàng)建兩種情況,顯式創(chuàng)建和隱含創(chuàng)建,,需要的朋友可以參考下面文章的具體內(nèi)容2021-09-09