Java使用線程同步解決線程安全問(wèn)題詳解
第一種方法:同步代碼塊:
作用:把出現(xiàn)線程安全的核心代碼上鎖
原理:每次只能一個(gè)線程進(jìn)入,執(zhí)行完畢后自行解鎖,其他線程才能進(jìn)來(lái)執(zhí)行
鎖對(duì)象要求:理論上,鎖對(duì)象只要對(duì)于當(dāng)前同時(shí)執(zhí)行的線程是同一個(gè)對(duì)象即可
缺點(diǎn):會(huì)干擾其他無(wú)關(guān)線程的執(zhí)行
所以,這種只是理論上的,了解即可,現(xiàn)實(shí)中并不會(huì)這樣用
public class 多線程_4線程同步 {
public static void main(String[] args) {
//定義線程類(lèi),創(chuàng)建一個(gè)共享的賬戶(hù)對(duì)象
account a=new account("abc",10000);
//創(chuàng)建兩個(gè)取錢(qián)的線程對(duì)象
new drawthread(a,"小明").start();
new drawthread(a,"小紅").start();
}
}
//取錢(qián)的線程類(lèi)
class drawthread extends Thread{
//接收處理的賬戶(hù)對(duì)象
private account acc;
public drawthread(account acc,String name){
super(name);
this.acc=acc;
}
public void run(){
//取錢(qián)
acc.drawmoney(10000);
}
}
class account{
private String cartId;
private double money;//賬戶(hù)余額
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) {
//先獲取是誰(shuí)來(lái)取錢(qián),線程名即是人名
String name=Thread.currentThread().getName();
//同步代碼塊
//作用:把出現(xiàn)線程安全的核心代碼上鎖
//原理:每次只能一個(gè)線程進(jìn)入,執(zhí)行完畢后自行解鎖,其他線程才能進(jìn)來(lái)執(zhí)行
//鎖對(duì)象要求:理論上,鎖對(duì)象只要對(duì)于當(dāng)前同時(shí)執(zhí)行的線程是同一個(gè)對(duì)象即可
//缺點(diǎn):會(huì)干擾其他無(wú)關(guān)線程的執(zhí)行
synchronized ("遇安") {//"鎖名自取,無(wú)意義"
//判斷賬戶(hù)是否夠錢(qián)
if(this.money>=money){
//取錢(qián)
System.out.println(name+"來(lái)取錢(qián)成功,取了:"+money);
//更新金額
this.money-=money;
System.out.println(name+"取錢(qián)后剩余:"+this.money);
}else{
//余額不足
System.out.println(name+"來(lái)取錢(qián),但余額不足!");
}
}
}
}規(guī)范上:建議使用共享資源作為鎖對(duì)象
對(duì)于實(shí)例化方法建議使用this作為鎖對(duì)象
對(duì)于靜態(tài)方法,建議使用字節(jié)碼(類(lèi)名.class)對(duì)象作為鎖對(duì)象
//接上文代碼
//實(shí)例化方法建議使用this作為鎖對(duì)象
synchronized (this) {
//判斷賬戶(hù)是否夠錢(qián)
if(this.money>=money){
//取錢(qián)
System.out.println(name+"來(lái)取錢(qián)成功,取了:"+money);
//更新金額
this.money-=money;
System.out.println(name+"取錢(qián)后剩余:"+this.money);
}else{
//余額不足
System.out.println(name+"來(lái)取錢(qián),但余額不足!");
}
}//靜態(tài)方法建議使用類(lèi)名.class作為鎖對(duì)象
//每次只有一個(gè)線程能鎖這個(gè)類(lèi),而類(lèi)也是唯一的
public static void run(){
synchronized(account.class){
}
}第二種方法:同步方法

//同步方法
public synchronized void drawmoney(double money) {
//先獲取是誰(shuí)來(lái)取錢(qián),線程名即是人名
String name=Thread.currentThread().getName();
//判斷賬戶(hù)是否夠錢(qián)
if(this.money>=money){
//取錢(qián)
System.out.println(name+"來(lái)取錢(qián)成功,取了:"+money);
//更新金額
this.money-=money;
System.out.println(name+"取錢(qián)后剩余:"+this.money);
}else{
//余額不足
System.out.println(name+"來(lái)取錢(qián),但余額不足!");
}
}那么同步代碼塊和同步方法哪個(gè)好一點(diǎn)呢?
答案是:同步代碼塊
因?yàn)橥酱a塊鎖的范圍更小一點(diǎn),同步方法鎖的范圍更大一點(diǎn)
但其實(shí)在現(xiàn)實(shí)中同步方法用的更多一點(diǎn),因?yàn)榇a簡(jiǎn)潔好寫(xiě)一點(diǎn),更方便
第三種方法:Lock鎖
JDK5后出現(xiàn),更加靈活方便
Lock是接口不能直接實(shí)例化,我們需要采用它的實(shí)現(xiàn)類(lèi)ReentrantLock來(lái)構(gòu)建Lock鎖對(duì)象
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class 多線程_4線程同步Lock鎖 {
public static void main(String[] args) {
//定義線程類(lèi),創(chuàng)建一個(gè)共享的賬戶(hù)對(duì)象
account a=new account("abc",10000);
//創(chuàng)建兩個(gè)取錢(qián)的線程對(duì)象
new drawthread(a,"小明").start();
new drawthread(a,"小紅").start();
}
}
//取錢(qián)的線程類(lèi)
class drawthread2 extends Thread{
//接收處理的賬戶(hù)對(duì)象
private account acc;
public drawthread2(account acc,String name){
super(name);
this.acc=acc;
}
public void run(){
//取錢(qián)
acc.drawmoney(10000);
}
}
class account2{
private String cartId;
private double money;//賬戶(hù)余額
//final修飾后:鎖對(duì)象是唯一的和不可替換的
//Lock是接口不能直接實(shí)例化,我們需要采用它的實(shí)現(xiàn)類(lèi)ReentrantLock來(lái)構(gòu)建Lock鎖對(duì)象
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) {
//先獲取是誰(shuí)來(lái)取錢(qián),線程名即是人名
String name=Thread.currentThread().getName();
lock.lock();//上鎖
//判斷賬戶(hù)是否夠錢(qián)
try {
if(this.money>=money){
//取錢(qián)
System.out.println(name+"來(lái)取錢(qián)成功,取了:"+money);
//更新金額
this.money-=money;
System.out.println(name+"取錢(qián)后剩余:"+this.money);
}else{
//余額不足
System.out.println(name+"來(lái)取錢(qián),但余額不足!");
}
//防止代碼出現(xiàn)bug而不能解鎖
} finally {
lock.unlock();//解鎖
}
}
}到此這篇關(guān)于Java使用線程同步解決線程安全問(wèn)題詳解的文章就介紹到這了,更多相關(guān)Java線程同步內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot3.2.2整合MyBatis Plus3.5.5的詳細(xì)過(guò)程
這篇文章給大家介紹了SpringBoot3.2.2整合MyBatis Plus3.5.5的詳細(xì)過(guò)程,文中通過(guò)代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-01-01
Java中的ConcurrentLinkedQueue松散隊(duì)列解析
這篇文章主要介紹了Java中的ConcurrentLinkedQueue松散隊(duì)列解析,鏈表是松散的,鏈表節(jié)點(diǎn)并不都是有效的,允許存在無(wú)效節(jié)點(diǎn)val=null,但是只有最后一個(gè)節(jié)點(diǎn)才能next=null,需要的朋友可以參考下2023-12-12
idea快速搭建spring cloud注冊(cè)中心與注冊(cè)的方法
這篇文章主要介紹了idea快速搭建spring cloud注冊(cè)中心與注冊(cè)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
淺析SpringBoot及環(huán)境搭建過(guò)程
Spring Boot是由Pivotal團(tuán)隊(duì)提供的全新框架,其設(shè)計(jì)目的是用來(lái)簡(jiǎn)化新Spring應(yīng)用的初始搭建以及開(kāi)發(fā)過(guò)程.這篇文章主要介紹了SpringBoot介紹及環(huán)境搭建,需要的朋友可以參考下2018-01-01
IntelliJ IDEA設(shè)置Tabs實(shí)現(xiàn)同時(shí)打開(kāi)多個(gè)文件且分行顯示
今天小編就為大家分享一篇關(guān)于IntelliJ IDEA設(shè)置Tabs實(shí)現(xiàn)同時(shí)打開(kāi)多個(gè)文件且分行顯示,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-10-10
Java創(chuàng)建對(duì)象(顯式創(chuàng)建和隱含創(chuàng)建)
本文詳細(xì)介紹對(duì)象的創(chuàng)建,在 Java 語(yǔ)言中創(chuàng)建對(duì)象分顯式創(chuàng)建與隱含創(chuàng)建兩種情況,顯式創(chuàng)建和隱含創(chuàng)建,,需要的朋友可以參考下面文章的具體內(nèi)容2021-09-09

