Java使用線程同步解決線程安全問題詳解
第一種方法:同步代碼塊:
作用:把出現(xiàn)線程安全的核心代碼上鎖
原理:每次只能一個線程進入,執(zhí)行完畢后自行解鎖,其他線程才能進來執(zhí)行
鎖對象要求:理論上,鎖對象只要對于當前同時執(zhí)行的線程是同一個對象即可
缺點:會干擾其他無關(guān)線程的執(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í)行的線程是同一個對象即可
//缺點:會干擾其他無關(guān)線程的執(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();//解鎖
}
}
}到此這篇關(guān)于Java使用線程同步解決線程安全問題詳解的文章就介紹到這了,更多相關(guān)Java線程同步內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot3.2.2整合MyBatis Plus3.5.5的詳細過程
這篇文章給大家介紹了SpringBoot3.2.2整合MyBatis Plus3.5.5的詳細過程,文中通過代碼示例給大家介紹的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2024-01-01
Java中的ConcurrentLinkedQueue松散隊列解析
這篇文章主要介紹了Java中的ConcurrentLinkedQueue松散隊列解析,鏈表是松散的,鏈表節(jié)點并不都是有效的,允許存在無效節(jié)點val=null,但是只有最后一個節(jié)點才能next=null,需要的朋友可以參考下2023-12-12
idea快速搭建spring cloud注冊中心與注冊的方法
這篇文章主要介紹了idea快速搭建spring cloud注冊中心與注冊的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07
IntelliJ IDEA設(shè)置Tabs實現(xiàn)同時打開多個文件且分行顯示
今天小編就為大家分享一篇關(guān)于IntelliJ IDEA設(shè)置Tabs實現(xiàn)同時打開多個文件且分行顯示,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-10-10
Java創(chuàng)建對象(顯式創(chuàng)建和隱含創(chuàng)建)
本文詳細介紹對象的創(chuàng)建,在 Java 語言中創(chuàng)建對象分顯式創(chuàng)建與隱含創(chuàng)建兩種情況,顯式創(chuàng)建和隱含創(chuàng)建,,需要的朋友可以參考下面文章的具體內(nèi)容2021-09-09

