Java解決線程安全的兩種方式分享
synchornized與lock的不同
synchronized機(jī)制在執(zhí)行完相應(yīng)的同步代碼以后,自動(dòng)的釋放同步監(jiān)視器
lock需要手動(dòng)的啟動(dòng)同步(Lock()),同時(shí)結(jié)束同步也需要使用手動(dòng)的實(shí)現(xiàn)(unlock())
synchornized方法實(shí)現(xiàn)線程同步方法
Synchronized 是 Java 中比較常用的實(shí)現(xiàn)線程安全的機(jī)制之一,它可以應(yīng)用于方法或代碼塊上,來(lái)保證同一時(shí)刻只有一個(gè)線程能夠訪問(wèn)到被加鎖的資源。使用 Synchronized 的方式主要有兩種:通過(guò)修飾方法實(shí)現(xiàn)同步,或者使用 synchronized 代碼塊實(shí)現(xiàn)同步。在并發(fā)環(huán)境下,Synchronized 可以確保對(duì)同步塊的訪問(wèn)是互斥的,避免了競(jìng)爭(zhēng)情況的產(chǎn)生。
public class ThreadBankTest { public static void main(String[] args) { Account account = new Account(0); Customer customer = new Customer(account); Customer customer2 = new Customer(account); customer.setName("甲"); customer2.setName("乙"); customer.start(); customer2.start(); } } class Customer extends Thread { private Account account; public Customer(Account account) { this.account = account; } @Override public void run() { for (int i = 0; i < 3; i++) { account.deposit(1000); } } } class Account { private int balance; public Account(int balance) { this.balance = balance; } //存錢(qián) public synchronized void deposit(int money) { if (money > 0) { balance += money; System.out.println(Thread.currentThread().getName()+"存錢(qián)成功"+balance); } } }
但是,Synchronized 也存在一些問(wèn)題。由于 Synchronized 內(nèi)置于 Java 虛擬機(jī)中,因此在獲取鎖的過(guò)程中還包含了一些“無(wú)謂的”開(kāi)銷(xiāo)。此外,Synchronized 在性能和靈活性方面都不如 Lock。
Lock實(shí)現(xiàn)線程同步的方法
Lock 是 Java 并發(fā)庫(kù)中提供的一種訪問(wèn)并發(fā)共享資源的方式,相比于 Synchronized,Lock 更靈活,更高效,提供了更多的功能。Lock 接口實(shí)際上是一組格式良好且相互獨(dú)立的線程控制方法,它可以被其他類(lèi)實(shí)現(xiàn)來(lái)提供鎖定的實(shí)現(xiàn)。使用 Lock 可以支持多個(gè) Condition(條件隊(duì)列),在同時(shí)滿(mǎn)足某些條件時(shí)由不同的線程執(zhí)行任務(wù),從而更加靈活地控制線程的等待、喚醒和通知;并且可以支持可重入鎖和公平鎖的實(shí)現(xiàn),提高了線程的競(jìng)爭(zhēng)程度,避免了死鎖等問(wèn)題。
public class ThreadBankTest2 { public static void main(String[] args) { Account2 account2 = new Account2(0); Customer2 customer = new Customer2(account2); Customer2 customer2 = new Customer2(account2); customer.setName("甲"); customer2.setName("乙"); customer.start(); customer2.start(); } } class Customer2 extends Thread { private Account2 account; public Customer2(Account2 account) { this.account = account; } @Override public void run() { for (int i = 0; i < 3; i++) { account.deposit(1000); } } } class Account2 { private int balance; //1.實(shí)例化ReentrantLock private ReentrantLock lock = new ReentrantLock(); public Account2(int balance) { this.balance = balance; } //存錢(qián) public void deposit(int money) { try { //2.調(diào)用lock方法:要把要同步的代碼放入到try中,try后面的代碼就是要實(shí)現(xiàn)同步代碼 lock.lock(); if (money > 0) { balance += money; System.out.println(Thread.currentThread().getName()+"存錢(qián)成功"+balance); } } finally { //3.給lock解鎖unlock lock.unlock(); } } }
但是,也需要注意使用 Lock 時(shí)可能存在的潛在問(wèn)題。Lock 是一個(gè)接口,因此使用前需要根據(jù)具體場(chǎng)景選擇適當(dāng)?shù)膶?shí)現(xiàn)類(lèi);如果不恰當(dāng)?shù)厥褂?Lock 可能會(huì)導(dǎo)致系統(tǒng)崩潰或性能下降,并且在實(shí)踐中必須手動(dòng)獲取和釋放鎖。此外,使用 Lock 方式還需要使用 try-finally 塊保護(hù)臨界區(qū)代碼以確保一定會(huì)釋放鎖。
綜合而言,無(wú)論是使用 Synchronized 還是 Lock,都需要根據(jù)具體情況進(jìn)行選擇。Synchronized 是 Java 內(nèi)置的機(jī)制,在簡(jiǎn)單場(chǎng)合使用上較為方便,但是效率低下和靈活性不如 Lock,對(duì)于實(shí)現(xiàn)復(fù)雜的多線程編程,Lock 顯然是更好的選擇。無(wú)論是哪種方式,都需要謹(jǐn)慎使用,在不影響程序正確性的前提下,盡量去追求程序的高效性和可靠性。
到此這篇關(guān)于Java解決線程安全的兩種方式分享的文章就介紹到這了,更多相關(guān)Java線程安全內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot集成Druid出現(xiàn)異常報(bào)錯(cuò)的原因及解決
Druid 可以很好的監(jiān)控 DB 池連接和 SQL 的執(zhí)行情況,天生就是針對(duì)監(jiān)控而生的 DB 連接池。本文講述了Spring Boot集成Druid項(xiàng)目中discard long time none received connection異常的解決方法,出現(xiàn)此問(wèn)題的同學(xué)可以參考下2021-05-05通過(guò)Session案例分析一次性驗(yàn)證碼登錄
這篇文章主要介紹了通過(guò)Session案例分析一次性驗(yàn)證碼登錄,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-03-03Java聊天室之實(shí)現(xiàn)聊天室客戶(hù)端功能
這篇文章主要為大家詳細(xì)介紹了Java簡(jiǎn)易聊天室之實(shí)現(xiàn)聊天室客戶(hù)端功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以了解一下2022-11-11java HashMap通過(guò)value反查key的代碼示例
本文講解了java HashMap通過(guò)value反查key的方法,直接提供代碼供大家參考使用2013-11-11關(guān)于IDEA 2020.3 多窗口視圖丟失的問(wèn)題
這篇文章主要介紹了關(guān)于IDEA 2020.3 多窗口視圖丟失的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12java調(diào)用百度定位api服務(wù)獲取地理位置示例
java調(diào)用百度定位api服務(wù)獲取地理位置示例,大家參考使用吧2013-12-12關(guān)于@EnableGlobalMethodSecurity注解的用法解讀
這篇文章主要介紹了關(guān)于@EnableGlobalMethodSecurity注解的用法解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03java?freemarker實(shí)現(xiàn)動(dòng)態(tài)生成excel文件
這篇文章主要為大家詳細(xì)介紹了java如何通過(guò)freemarker實(shí)現(xiàn)動(dòng)態(tài)生成excel文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12