更新時(shí)間:2022-09-08 11:12:49 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽1884次
相信大家對(duì)Java ReentrantLock使用都有了一定的了解,ReentrantLock 類(lèi)實(shí)現(xiàn)了 Lock 接口,并在訪(fǎng)問(wèn)共享資源時(shí)為方法提供同步。操作共享資源的代碼被鎖定和解鎖方法的調(diào)用包圍。這為當(dāng)前工作線(xiàn)程提供了一個(gè)鎖定,并阻止了所有其他試圖鎖定共享資源的線(xiàn)程。
顧名思義,ReentrantLock 允許線(xiàn)程多次進(jìn)入資源鎖。當(dāng)線(xiàn)程第一次進(jìn)入鎖時(shí),保持計(jì)數(shù)設(shè)置為 1。在解鎖之前,線(xiàn)程可以重新進(jìn)入鎖,每次保持計(jì)數(shù)加一。對(duì)于每個(gè)解鎖請(qǐng)求,保持計(jì)數(shù)減 1,當(dāng)保持計(jì)數(shù)為 0 時(shí),資源被解鎖。
可重入鎖還提供了一個(gè)公平參數(shù),通過(guò)該參數(shù),鎖將遵循鎖請(qǐng)求的順序,即在線(xiàn)程解鎖資源后,鎖將轉(zhuǎn)到等待時(shí)間最長(zhǎng)的線(xiàn)程。這種公平模式是通過(guò)將 true 傳遞給鎖的構(gòu)造函數(shù)來(lái)設(shè)置的。
這些鎖的使用方式如下:
public void some_method()
{
reentrantlock.lock();
try
{
//Do some work
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
reentrantlock.unlock();
}
}
總是在 finally 塊中調(diào)用解鎖語(yǔ)句,以確保即使在方法體(try 塊)中拋出異常也能釋放鎖。
lock():調(diào)用 lock() 方法將保持計(jì)數(shù)加 1,如果共享資源最初是空閑的,則將鎖分配給線(xiàn)程。
unlock():調(diào)用unlock()方法將持有計(jì)數(shù)減1。當(dāng)這個(gè)計(jì)數(shù)達(dá)到零時(shí),資源被釋放。
tryLock():如果資源未被任何其他線(xiàn)程持有,則調(diào)用 tryLock() 返回 true,并且持有計(jì)數(shù)加 1。如果資源不是空閑的,則該方法返回 false,線(xiàn)程不會(huì)被阻塞,而是退出。
tryLock(long timeout, TimeUnit unit):根據(jù)方法,線(xiàn)程在退出前等待方法參數(shù)定義的一定時(shí)間段來(lái)獲取資源的鎖。
lockInterruptibly():如果資源空閑,則此方法獲取鎖,同時(shí)允許線(xiàn)程在獲取資源時(shí)被其他線(xiàn)程中斷。意思是如果當(dāng)前線(xiàn)程正在等待鎖,但是其他線(xiàn)程請(qǐng)求鎖,那么當(dāng)前線(xiàn)程將被中斷并立即返回而不獲取鎖。
getHoldCount():此方法返回資源上持有的鎖的數(shù)量。
isHeldByCurrentThread():如果當(dāng)前線(xiàn)程持有資源的鎖,則此方法返回 true。
在下面的教程中,我們將看一個(gè)可重入鎖的基本示例。
應(yīng)遵循的步驟
1.創(chuàng)建ReentrantLock的對(duì)象
2.創(chuàng)建一個(gè)worker(Runnable Object)來(lái)執(zhí)行并將鎖傳遞給對(duì)象
3.使用lock()方法獲取共享資源的鎖
4.工作完成后調(diào)用unlock()方法釋放鎖
下面是問(wèn)題陳述的實(shí)現(xiàn):
// Java code to illustrate Reentrant Locks
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;
class worker implements Runnable
{
String name;
ReentrantLock re;
public worker(ReentrantLock rl, String n)
{
re = rl;
name = n;
}
public void run()
{
boolean done = false;
while (!done)
{
//Getting Outer Lock
boolean ans = re.tryLock();
// Returns True if lock is free
if(ans)
{
try
{
Date d = new Date();
SimpleDateFormat ft = new SimpleDateFormat("hh:mm:ss");
System.out.println("task name - "+ name
+ " outer lock acquired at "
+ ft.format(d)
+ " Doing outer work");
Thread.sleep(1500);
// Getting Inner Lock
re.lock();
try
{
d = new Date();
ft = new SimpleDateFormat("hh:mm:ss");
System.out.println("task name - "+ name
+ " inner lock acquired at "
+ ft.format(d)
+ " Doing inner work");
System.out.println("Lock Hold Count - "+ re.getHoldCount());
Thread.sleep(1500);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
finally
{
//Inner lock release
System.out.println("task name - " + name +
" releasing inner lock");
re.unlock();
}
System.out.println("Lock Hold Count - " + re.getHoldCount());
System.out.println("task name - " + name + " work done");
done = true;
}
catch(InterruptedException e)
{
e.printStackTrace();
}
finally
{
//Outer lock release
System.out.println("task name - " + name +
" releasing outer lock");
re.unlock();
System.out.println("Lock Hold Count - " +
re.getHoldCount());
}
}
else
{
System.out.println("task name - " + name +
" waiting for lock");
try
{
Thread.sleep(1000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}
public class test
{
static final int MAX_T = 2;
public static void main(String[] args)
{
ReentrantLock rel = new ReentrantLock();
ExecutorService pool = Executors.newFixedThreadPool(MAX_T);
Runnable w1 = new worker(rel, "Job1");
Runnable w2 = new worker(rel, "Job2");
Runnable w3 = new worker(rel, "Job3");
Runnable w4 = new worker(rel, "Job4");
pool.execute(w1);
pool.execute(w2);
pool.execute(w3);
pool.execute(w4);
pool.shutdown();
}
}
樣品執(zhí)行
輸出:
任務(wù)名稱(chēng) - Job2 等待鎖定
任務(wù)名稱(chēng) - Job1 外部鎖在 09:49:42 獲取
任務(wù)名稱(chēng) - Job2 等待鎖定
任務(wù)名稱(chēng) - Job1 內(nèi)部鎖在 09:49:44 獲得
鎖定保持計(jì)數(shù) - 2
任務(wù)名稱(chēng) - Job2 等待鎖定
任務(wù)名稱(chēng) - Job2 等待鎖定
任務(wù)名稱(chēng) - Job1 釋放內(nèi)部鎖
鎖定保持計(jì)數(shù) - 1
任務(wù)名稱(chēng) - Job1 完成的工作
任務(wù)名稱(chēng) - Job1 釋放外部鎖
鎖定保持計(jì)數(shù) - 0
任務(wù)名稱(chēng) - Job3 外部鎖在 09:49:45 獲取
任務(wù)名稱(chēng) - Job2 等待鎖定
任務(wù)名稱(chēng) - 在 09:49:47 獲得的 Job3 內(nèi)部鎖正在做內(nèi)部工作
鎖定保持計(jì)數(shù) - 2
任務(wù)名稱(chēng) - Job2 等待鎖定
任務(wù)名稱(chēng) - Job2 等待鎖定
任務(wù)名稱(chēng) - Job3 釋放內(nèi)部鎖
鎖定保持計(jì)數(shù) - 1
任務(wù)名稱(chēng) - Job3 完成的工作
任務(wù)名稱(chēng) - Job3 釋放外鎖
鎖定保持計(jì)數(shù) - 0
任務(wù)名稱(chēng) - Job4 外部鎖在 09:49:48 獲取
任務(wù)名稱(chēng) - Job2 等待鎖定
任務(wù)名稱(chēng) - Job4 內(nèi)部鎖在 09:49:50 獲取
鎖定保持計(jì)數(shù) - 2
任務(wù)名稱(chēng) - Job2 等待鎖定
任務(wù)名稱(chēng) - Job2 等待鎖定
任務(wù)名稱(chēng) - Job4 釋放內(nèi)部鎖
鎖定保持計(jì)數(shù) - 1
任務(wù)名稱(chēng) - Job4 完成的工作
任務(wù)名稱(chēng) - Job4 釋放外鎖
鎖定保持計(jì)數(shù) - 0
任務(wù)名稱(chēng) - Job2 外部鎖在 09:49:52 獲取
任務(wù)名稱(chēng) - Job2 內(nèi)部鎖在 09:49:53 獲取
鎖定保持計(jì)數(shù) - 2
任務(wù)名稱(chēng) - Job2 釋放內(nèi)部鎖
鎖定保持計(jì)數(shù) - 1
任務(wù)名稱(chēng) - Job2 完成的工作
任務(wù)名稱(chēng) - Job2 釋放外部鎖
鎖定保持計(jì)數(shù) - 0
1.人們可能會(huì)忘記在 finally 塊中調(diào)用 unlock() 方法,從而導(dǎo)致程序出現(xiàn)錯(cuò)誤。確保在線(xiàn)程退出之前釋放鎖。
2.用于構(gòu)造鎖對(duì)象的公平參數(shù)會(huì)降低程序的吞吐量。
ReentrantLock 是同步的更好替代品,它提供了許多 synchronized 沒(méi)有提供的功能。然而,這些明顯好處的存在并不足以成為總是喜歡 ReentrantLock 進(jìn)行同步的充分理由。相反,根據(jù)您是否需要 ReentrantLock 提供的靈活性來(lái)做出決定。
以上就是關(guān)于“告訴你什么是Java中的可重入鎖”的介紹,大家如果對(duì)此比較感興趣,想了解更多相關(guān)知識(shí),可以關(guān)注一下動(dòng)力節(jié)點(diǎn)的Java多線(xiàn)程編程,里面有更豐富的知識(shí)等著大家去學(xué)習(xí),相信對(duì)大家一定會(huì)有所幫助的哦。
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
有基礎(chǔ) 直達(dá)就業(yè)
業(yè)余時(shí)間 高薪轉(zhuǎn)行
工作1~3年,加薪神器
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問(wèn)老師會(huì)電話(huà)與您溝通安排學(xué)習(xí)
初級(jí) 202925
初級(jí) 203221
初級(jí) 202629
初級(jí) 203743