天天看點

《Java并發程式設計從入門到精通》顯示鎖Lock和ReentrantLock

顯示鎖lock和reentrantlock

lock是一個接口提供了無條件的、可輪詢的、定時的、可中斷的鎖擷取操作,所有加鎖和解鎖的方法都是顯式的。包路徑是:java.util.concurrent.locks.lock。核心方法是lock(),unlock(),trylock(),實作類有reentrantlock, reentrantreadwritelock.readlock, reentrantreadwritelock.writelock。

看一下lock接口有如下方法:

public abstract interface lock

{

public abstract void lock();

public abstract void lockinterruptibly() throws interruptedexception;

public abstract boolean trylock();

public abstract boolean trylock(long paramlong , timeunit paramtimeunit) throws interruptedexception;

public abstract void unlock();

public abstract condition newcondition();

}

對應的解說如下:

void lock();擷取鎖。如果鎖不可用,出于線程排程目的,将禁用目前線程,并且在獲得鎖之前,該線程将一直處于休眠狀态。

void lockinterruptibly() throws interruptedexception;如果目前線程未被中斷,則擷取鎖。如果鎖可用,則擷取鎖,并立即傳回。如果鎖不可用,出于線程排程目的,将禁用目前線程,并且在發生以下兩種情況之一以前,該線程将一直處于休眠狀态:鎖由目前線程獲得;或者其他某個線程中斷 目前線程,并且支援對鎖擷取的中斷。如果目前線程:在進入此方法時已經設定了該線程的中斷狀态;或者在擷取鎖時被中斷 ,并且支援對鎖擷取的中斷,則将抛出  interruptedexception ,并清除目前線程的已中斷狀态。

boolean trylock();僅在調用時鎖為空閑狀态才擷取該鎖。如果鎖可用,則擷取鎖,并立即傳回值  true 。如果鎖不可用,則此方法将立即傳回值  false 。通常對于那些不是必須擷取鎖的操作可能有用。

boolean trylock(long time, timeunit unit) throws interruptedexception;如果鎖在給定的等待時間内空閑,并且目前線程未被中斷,則擷取鎖。如果鎖可用,則此方法将立即傳回值  true 。如果鎖不可用,出于線程排程目的,将禁用目前線程,并且在發生以下三種情況之一前,該線程将一直處于休眠狀态:

void unlock();釋放鎖。對應于lock()、trylock()、trylock(xx)、lockinterruptibly()等操作,如果成功的話應該對應着一個unlock(),這樣可以避免死鎖或者資源浪費。

newcondition() 傳回用來與此 lock 執行個體一起使用的 condition 執行個體。

reentrantlock是lock的實作類,是一個互斥的同步器,它具有擴充的能力。在競争條件下,reentrantlock 的實作要比現在的 synchronized 實作更具有可伸縮性。(有可能在 jvm 的将來版本中改進 synchronized 的競争性能)這意味着當許多線程都競争相同鎖定時,使用 reentrantlock 的吞吐量通常要比 synchronized 好。換句話說,當許多線程試圖通路 reentrantlock 保護的共享資源時,jvm 将花費較少的時間來排程線程,而用更多個時間執行線程。雖然 reentrantlock 類有許多優點,但是與同步相比,它有一個主要缺點 — 它可能忘記釋放鎖定。reentrantlock實在工作中對方法塊加鎖使用頻率最高的。

使用方法如下:

class x {

private final reentrantlock lock = new reentrantlock();

// …

public void m() {

lock.lock(); // 獲得鎖

try {

// … 方法體

} finally {

lock.unlock();//解鎖

lock與synchronized 的比較:

1:lock使用起來比較靈活,但是必須有釋放鎖的動作;

2:lock必須手動釋放和開啟鎖,synchronized 不需要;

3:lock隻适用與代碼塊鎖,而synchronized 對象之間的互斥關系;

請注意以下兩種方式的差別:

第一種方式:兩個方法之間的鎖是獨立的。如下:

public class reentrantlockdemo {

public static void main(string[] args) {

final count ct = new count();

for (int i = 0; i < 2; i++) {

new thread() {

@override

public void run() {

ct.get();

}.start();

ct.put();

class count {

public void get() {

final reentrantlock lock = new reentrantlock();

lock.lock(); // 加鎖

system. out.println(thread.currentthread().getname() + “get begin”);

thread. sleep(1000l);// 模仿幹活

system. out.println(thread.currentthread().getname() + “get end”);

lock.unlock(); // 解鎖

} catch (interruptedexception e) {

e.printstacktrace();

public void put() {

system. out.println(thread.currentthread().getname() + “put begin”);

system. out.println(thread.currentthread().getname() + “put end”);

運作結果如下(每次運作結果都是不一樣的,仔細體會一下):

thread-0get begin

thread-1get begin

thread-2put begin

thread-3put begin

thread-0get end

thread-2put end

thread-3put end

thread-1get end

第二種方式,兩個方法之間使用相同的鎖。

reentrantlockdemo 類的内容不變,将count中的reentrantlock改成全局變量,如下所示:

final reentrantlock lock = new reentrantlock();

運作結果如下(每次運作結果一樣的,仔細體會一下):