淺聊一下Java中的鎖機(jī)制
Java中的鎖機(jī)制是保證多線(xiàn)程并發(fā)訪問(wèn)共享資源安全性的重要手段之一。Java提供了兩種類(lèi)型的鎖機(jī)制:synchronized關(guān)鍵字和Lock接口。本文將介紹這兩種鎖機(jī)制的原理及使用方法,并通過(guò)代碼示例講解它們的使用。
synchronized關(guān)鍵字
synchronized關(guān)鍵字是Java語(yǔ)言?xún)?nèi)置的一種鎖機(jī)制,它可以用來(lái)實(shí)現(xiàn)對(duì)代碼塊或方法的同步控制。synchronized可以保證在同一時(shí)刻只有一個(gè)線(xiàn)程可以執(zhí)行被鎖定的代碼塊或方法,其他線(xiàn)程則需要等待鎖釋放后才能繼續(xù)執(zhí)行。這種機(jī)制可以避免多個(gè)線(xiàn)程同時(shí)對(duì)共享資源進(jìn)行操作而引發(fā)的數(shù)據(jù)不一致問(wèn)題。
原理
synchronized鎖的實(shí)現(xiàn)依賴(lài)于Java對(duì)象頭中的Mark Word(標(biāo)記字段)。每個(gè)Java對(duì)象都有一個(gè)Mark Word,用于存儲(chǔ)對(duì)象的元數(shù)據(jù)信息。synchronized鎖就是利用Mark Word中的標(biāo)志位來(lái)實(shí)現(xiàn)的。當(dāng)一個(gè)線(xiàn)程獲取鎖時(shí),它會(huì)將對(duì)象頭中的標(biāo)志位設(shè)置為鎖定狀態(tài),其他線(xiàn)程在嘗試獲取鎖時(shí),發(fā)現(xiàn)標(biāo)志位已被設(shè)置為鎖定狀態(tài),就會(huì)進(jìn)入等待狀態(tài),直到鎖被釋放。
使用方法
synchronized可以用來(lái)修飾代碼塊和方法,具體用法如下:
代碼塊同步
synchronized (lockObject) { // 需要同步的代碼塊 }
其中,lockObject是一個(gè)Java對(duì)象,用來(lái)作為鎖對(duì)象。當(dāng)線(xiàn)程進(jìn)入同步塊時(shí),它會(huì)嘗試獲取lockObject對(duì)象的鎖,如果鎖已被其他線(xiàn)程持有,則該線(xiàn)程會(huì)進(jìn)入等待狀態(tài),直到鎖被釋放。
方法同步
public synchronized void method() { // 需要同步的代碼 }
當(dāng)一個(gè)線(xiàn)程調(diào)用被synchronized修飾的方法時(shí),它會(huì)嘗試獲取當(dāng)前對(duì)象的鎖,如果鎖已被其他線(xiàn)程持有,則該線(xiàn)程會(huì)進(jìn)入等待狀態(tài),直到鎖被釋放。需要注意的是,方法同步只對(duì)同一對(duì)象有效,對(duì)不同對(duì)象的方法調(diào)用并不會(huì)互斥。
代碼示例
下面是一個(gè)使用synchronized關(guān)鍵字實(shí)現(xiàn)線(xiàn)程同步的示例代碼。該代碼定義了一個(gè)Counter類(lèi),包含一個(gè)count屬性和兩個(gè)方法:increment()和decrement(),分別用于對(duì)count進(jìn)行加1和減1操作。increment()和decrement()方法都使用synchronized關(guān)鍵字進(jìn)行同步,以確保對(duì)count的操作是線(xiàn)程安全的。
public class Counter { private int count; ? public synchronized void increment() { count++; } ? public synchronized void decrement() { count--; } ? public int getCount() { return count; } }
Lock接口
除了synchronized關(guān)鍵字外,Java還提供了Lock接口來(lái)實(shí)現(xiàn)鎖機(jī)制。相對(duì)于synchronized,Lock接口提供了更加靈活的鎖定方式和更加精細(xì)的控制,例如可以實(shí)現(xiàn)公平鎖和非公平鎖、可重入鎖等。
原理
Lock接口的實(shí)現(xiàn)原理和synchronized類(lèi)似,都是通過(guò)占用對(duì)象的鎖來(lái)實(shí)現(xiàn)同步控制。不同的是,Lock接口提供了更多的方法來(lái)控制鎖的獲取和釋放,例如tryLock()方法可以嘗試獲取鎖,如果獲取失敗則不會(huì)阻塞線(xiàn)程,而是直接返回。
使用方法
Lock接口的使用相對(duì)比較復(fù)雜,需要注意鎖的獲取和釋放時(shí)機(jī),以避免死鎖等問(wèn)題。下面是一個(gè)簡(jiǎn)單的Lock接口使用示例:
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; ? public class Counter { private int count; private Lock lock = new ReentrantLock(); ? public void increment() { lock.lock(); try { count++; } finally { lock.unlock(); } } ? public void decrement() { lock.lock(); try { count--; } finally { lock.unlock(); } } ? public int getCount() { return count; } }
在上述代碼中,我們使用了ReentrantLock類(lèi)來(lái)實(shí)現(xiàn)Lock接口。在increment()和decrement()方法中,我們使用了lock()方法獲取鎖,使用了unlock()方法釋放鎖。需要注意的是,為了避免線(xiàn)程因異常而無(wú)法釋放鎖,我們將獲取鎖和釋放鎖的代碼放在了try...finally塊中。
公平鎖與非公平鎖
Lock接口的實(shí)現(xiàn)可以是公平鎖(FairLock)或非公平鎖(NonFairLock)。公平鎖指的是鎖的獲取是按照請(qǐng)求的先后順序進(jìn)行的,而非公平鎖則不保證鎖的獲取順序。在實(shí)際應(yīng)用中,公平鎖可以保證所有線(xiàn)程都有平等的機(jī)會(huì)獲取鎖,但是會(huì)降低性能,因?yàn)榫€(xiàn)程需要等待前面的線(xiàn)程釋放鎖;而非公平鎖則可能會(huì)導(dǎo)致某些線(xiàn)程一直無(wú)法獲取鎖,但是會(huì)提高性能,因?yàn)榫€(xiàn)程可以不需要等待直接獲取鎖。
可重入鎖
Lock接口還提供了可重入鎖(ReentrantLock),它可以允許一個(gè)線(xiàn)程多次獲取同一把鎖。這種鎖機(jī)制可以避免死鎖等問(wèn)題,并且可以提高代碼的可讀性和可維護(hù)性。例如,在某個(gè)方法中調(diào)用了另一個(gè)同步方法,如果使用synchronized關(guān)鍵字,需要在內(nèi)部方法中再次獲取鎖才能保證線(xiàn)程安全;而使用可重入鎖則可以直接調(diào)用。
Lock接口提供了更多的方法來(lái)控制鎖的獲取和釋放,例如tryLock()方法可以嘗試獲取鎖,如果獲取失敗則不會(huì)阻塞線(xiàn)程,而是直接返回;lockInterruptibly()方法可以在獲取鎖時(shí)響應(yīng)中斷,可以有效避免死鎖等問(wèn)題。
代碼示例
下面是一個(gè)使用Lock接口實(shí)現(xiàn)讀寫(xiě)鎖的示例:
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; ? public class MyReadWriteLock { private int value; private ReadWriteLock lock = new ReentrantReadWriteLock(); private Lock readLock = lock.readLock(); private Lock writeLock = lock.writeLock(); ? public int getValue() { readLock.lock(); try { return value; } finally { readLock.unlock(); } } ? public void setValue(int value) { writeLock.lock(); try { this.value = value; } finally { writeLock.unlock(); } } }
在上述代碼中,我們使用了ReentrantReadWriteLock類(lèi)來(lái)實(shí)現(xiàn)讀寫(xiě)鎖。讀寫(xiě)鎖可以同時(shí)支持多個(gè)讀操作,但只能有一個(gè)寫(xiě)操作,因此可以提高代碼的并發(fā)性能。在getValue()方法中,我們使用了讀鎖來(lái)獲取當(dāng)前的value值,而在setValue()方法中,我們使用了寫(xiě)鎖來(lái)設(shè)置新的value值。
總結(jié)
Lock接口相對(duì)于synchronized關(guān)鍵字提供了更加靈活的鎖定方式和更加精細(xì)的控制。使用Lock接口可以避免死鎖等問(wèn)題,并且可以提高代碼的可讀性和可維護(hù)性。在實(shí)際應(yīng)用中,需要注意鎖的獲取和釋放時(shí)機(jī),以避免死鎖等問(wèn)題。同時(shí),還需要根據(jù)實(shí)際情況選擇公平鎖和非公平鎖,以及可重入鎖等不同的鎖類(lèi)型。
到此這篇關(guān)于淺聊一下Java中的鎖機(jī)制的文章就介紹到這了,更多相關(guān)Java鎖機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java中HashSet的特點(diǎn)及實(shí)例用法
在本篇文章里小編給大家整理的是一篇關(guān)于java中HashSet的特點(diǎn)及實(shí)例用法,有興趣的朋友們可以學(xué)習(xí)下。2021-04-04springboot項(xiàng)目引入外部jar包的詳細(xì)圖文教程
在項(xiàng)目中有時(shí)候需要引入外部jar包,啟動(dòng)運(yùn)行,下面這篇文章主要給大家介紹了關(guān)于springboot項(xiàng)目引入外部jar包的詳細(xì)圖文教程,需要的朋友可以參考下2023-09-09基于java線(xiàn)程池讀取單個(gè)SQL數(shù)據(jù)庫(kù)表
這篇文章主要為大家詳細(xì)介紹了基于java線(xiàn)程池讀取單個(gè)SQL數(shù)據(jù)庫(kù)表,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08SpringBoot通過(guò)ip獲取歸屬地的幾種方式分享
在日常我們逛網(wǎng)站的時(shí)候會(huì)發(fā)現(xiàn)我們登錄后會(huì)出現(xiàn)歸屬地信息,例如:我在廣州登錄會(huì)顯示廣東廣州,有些更加精確的會(huì)顯示到區(qū)縣,那么我們來(lái)看看有哪些方式來(lái)獲取歸屬地信息,今天我們來(lái)聊一聊2023-09-09Nacos的單機(jī)模式啟動(dòng)失敗問(wèn)題及解決
這篇文章主要介紹了Nacos的單機(jī)模式啟動(dòng)失敗問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07如何使用Playwright對(duì)Java API實(shí)現(xiàn)自動(dòng)視覺(jué)測(cè)試
這篇文章主要介紹了如何使用Playwright對(duì)Java API實(shí)現(xiàn)自動(dòng)視覺(jué)測(cè)試,幫助大家更好的理解和使用Playwright,感興趣的朋友可以了解下2021-01-01Java單表實(shí)現(xiàn)評(píng)論回復(fù)功能(多種實(shí)現(xiàn)方式)
這篇文章主要介紹了Java單表實(shí)現(xiàn)評(píng)論回復(fù)功能,大家都知道評(píng)論功能有多種實(shí)現(xiàn)方式,本文逐一給大家詳細(xì)講解,需要的朋友可以參考下2023-03-03解決idea每次新建項(xiàng)目都需要重新指定maven目錄
這篇文章主要介紹了解決idea每次新建項(xiàng)目都需要配置maven,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09