天天看點

java trylock逾時_【java】lock.tryLock()方法的使用

package concurrent;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class TestTryLock {

private List list = new ArrayList();

private Lock lock = new ReentrantLock();

public static void main(String[] args) {

final TestTryLock test = new TestTryLock();

new Thread("第一個線程 ") {

@Override

public void run() {

test.doSomething(Thread.currentThread());

}

}.start();

new Thread("第二個線程 ") {

@Override

public void run() {

test.doSomething(Thread.currentThread());

}

}.start();

}

public void doSomething(Thread thread) {

if (lock.tryLock()) {

try {

System.out.println(thread.getName() + "得到了鎖.");

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

list.add(i);

}

} catch (Exception e) {

e.printStackTrace();

} finally {

System.out.println(thread.getName() + "釋放了鎖.");

lock.unlock();

}

} else {

System.out.println(thread.getName() + "擷取鎖失敗.");

}

}

}

以上代碼運作結果如下:

第一個線程 得到了鎖.

第一個線程 釋放了鎖.

第二個線程 得到了鎖.

第二個線程 釋放了鎖.

package concurrent;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class TestTryLock {

private List list = new ArrayList();

private Lock lock = new ReentrantLock();

public static void main(String[] args) {

final TestTryLock test = new TestTryLock();

new Thread("第一個線程 ") {

@Override

public void run() {

test.doSomething(Thread.currentThread());

}

}.start();

new Thread("第二個線程 ") {

@Override

public void run() {

test.doSomething(Thread.currentThread());

}

}.start();

}

public void doSomething(Thread thread) {

if (lock.tryLock()) {

try {

System.out.println(thread.getName() + "得到了鎖.");

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

list.add(i);

Thread.sleep(10);

}

} catch (Exception e) {

e.printStackTrace();

} finally {

System.out.println(thread.getName() + "釋放了鎖.");

lock.unlock();

}

} else {

System.out.println(thread.getName() + "擷取鎖失敗.");

}

}

}

運作結果如下:

第二個線程 得到了鎖.

第一個線程 擷取鎖失敗.

第二個線程 釋放了鎖.

問題如下:

我知道lock()方法去擷取鎖,當擷取不到鎖的時候,會一直等待。直到擷取到鎖。

tryLock()方法擷取鎖的時候,制作一次試探,如果擷取鎖失敗,就不會一直等待的。如果是這樣的話,如我Demo所示的這樣,在業務邏輯中使用tryLock很容易造成程式不可控。比較疑惑這個tryLock的使用方法。。求大神解釋。。謝謝~~

回答

這個最好把Lock的四個鎖法都比較一下(容我copy些東西):

void lock();

If the lock is not available then the current thread becomes disabled for thread scheduling purposes and lies dormant until the lock has been acquired.

在等待擷取鎖的過程中休眠并禁止一切線程排程

void lockInterruptibly() throws InterruptedException;

If the lock is not available then the current thread becomes disabled for thread scheduling purposes and lies dormant until one of two things happens:

The lock is acquired by the current thread; or Some other thread interrupts the current thread, and interruption of lock acquisition is supported.

在等待擷取鎖的過程中可被中斷

boolean tryLock();

Acquires the lock if it is available and returns immediately with the value true. If the lock is not available then this method will return immediately with the value false.

擷取到鎖并傳回true;擷取不到并傳回false

*boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

If the lock is available this method returns immediately with the value true. If the lock is not available then the current thread becomes disabled for thread scheduling purposes and lies dormant until one of three things happens:The lock is acquired by the current thread; or Some other thread interrupts the current thread, and interruption of lock acquisition is supported; or The specified waiting time elapses.

在指定時間内等待擷取鎖;過程中可被中斷

假如線程A和線程B使用同一個鎖LOCK,此時線程A首先擷取到鎖LOCK.lock(),并且始終持有不釋放。如果此時B要去擷取鎖,有四種方式:

LOCK.lock(): 此方式會始終處于等待中,即使調用B.interrupt()也不能中斷,除非線程A調用LOCK.unlock()釋放鎖。

LOCK.lockInterruptibly(): 此方式會等待,但當調用B.interrupt()會被中斷等待,并抛出InterruptedException異常,否則會與lock()一樣始終處于等待中,直到線程A釋放鎖。

LOCK.tryLock(): 該處不會等待,擷取不到鎖并直接傳回false,去執行下面的邏輯。

LOCK.tryLock(10, TimeUnit.SECONDS):該處會在10秒時間内處于等待中,但當調用B.interrupt()會被中斷等待,并抛出InterruptedException。10秒時間内如果線程A釋放鎖,會擷取到鎖并傳回true,否則10秒過後會擷取不到鎖并傳回false,去執行下面的邏輯。

是否會造成 程式不可控, 不在于這幾種方式本身,在于業務類别和使用邏輯上。

為什麼說會造成程式不可控呢,調用tryLock方法之後會立即傳回結果,根據是否獲得鎖然後做出相應的業務操作,相比較于lock方法會一直阻塞這本身已經使程式更可控了。

不同的方法有不同的用處啊,隻是應用的場景不同,不是不可控

題主這裡對程式可控的了解是指每一個任務都按照要求執行,但我覺得既然用tryLock()這個非阻塞的場景,就是要允許某些任務不執行(比如防止重複送出業務),或逾時不執行(比如防止資源等待隊列溢出)等。