当线程请求内部锁时,如果锁已经被占用,则请求线程必须无条件等待,这往往会造成很多奇怪问题,相互等待是造成死锁的重要原因之一,著名的哲学家就餐问题就是个典型的案例。新的Lock锁提供了尝试获取锁失败自动放弃的方法tryLock(),具有更完善的错误恢复机制。
1
2
|
boolean
tryLock();
boolean
tryLock(
long
time, TimeUnit unit)
throws
InterruptedException;
|
Lock接口定义了两个重载tryLock()函数,第一个函数表示如果锁可用则立即获得锁并返回true,如果请求的锁当前不可用则立即放弃并返回false;第二个函数表示如果请求的锁当前可用则立即获得锁并返回true,如果锁不可用则等待指定的时间,在等待期间,线程可能被中断,可能获得锁,如果等待时间结束还未获取到锁则自动放弃并返回false,明显相对第一个函数提供了更多的灵活性。
当然我们还可以自己利用循环轮询调用tryLock(),以实现轮询锁等,实现更多的灵活机制,这就是Lock相对内部锁的好处,特别是当线程需要同时获取多把不同锁时,tryLock()大有用处。
举一个实际简单应用场景,假设我们有个定时任务,定时清理垃圾,但每次清理垃圾耗费的时间可能不同,如果新任务发现上个任务还没执行完就自己结束,因为不需要这次任务。其实ScheduledExecutorService.scheduleAtFixedRate()函数就提供这样的功能,每个定时任务都是等上个任务完成才开始执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
import
java.util.concurrent.Executors;
import
java.util.concurrent.ScheduledExecutorService;
import
java.util.concurrent.TimeUnit;
import
java.util.concurrent.locks.Lock;
import
java.util.concurrent.locks.ReentrantLock;
public
class
TestTryLock {
private
Lock mLock;
private
volatile
boolean
isTimeoutEnabled;
public
TestTryLock(){
this
.mLock =
new
ReentrantLock();
this
.isTimeoutEnabled =
false
;
}
public
void
clearRubbish()
throws
InterruptedException{
if
(mLock.tryLock()){
try
{
System.out.println(Thread.currentThread().getName() +
":get the lock successfully."
);
int
estTime = (
int
) (
10
* Math.random());
System.out.println(Thread.currentThread().getName() +
":estimate time for finish job:"
+ estTime);
TimeUnit.SECONDS.sleep(estTime);
}
finally
{
mLock.unlock();
}
}
else
{
System.out.println(Thread.currentThread().getName() +
":failed to get the lock."
);
}
}
public
void
clearRubbishWithTimeout()
throws
InterruptedException{
if
(mLock.tryLock(
2
, TimeUnit.SECONDS)){
try
{
System.out.println(Thread.currentThread().getName() +
":get the lock successfully by waiting 2 seconds."
);
int
estTime = (
int
) (
10
* Math.random());
System.out.println(Thread.currentThread().getName() +
":estimate time for finish job:"
+ estTime);
TimeUnit.SECONDS.sleep(estTime);
}
finally
{
mLock.unlock();
}
}
else
{
System.out.println(Thread.currentThread().getName() +
":failed to get the lock after waiting 2 seconds."
);
}
}
private
class
Worker
implements
Runnable{
@Override
public
void
run() {
try
{
if
(isTimeoutEnabled){
clearRubbishWithTimeout();
}
else
{
clearRubbish();
}
isTimeoutEnabled = !isTimeoutEnabled;
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
private
class
TimerWorker
implements
Runnable{
@Override
public
void
run() {
new
Thread(
new
Worker()).start();
}
}
public
static
void
main(String[] args) {
TestTryLock testTryLock =
new
TestTryLock();
ScheduledExecutorService service = Executors.newScheduledThreadPool(
1
);
service.scheduleAtFixedRate(testTryLock.
new
TimerWorker(),
0
,
3
, TimeUnit.SECONDS);
}
}
|
本文转自sarchitect 51CTO博客,原文链接:http://blog.51cto.com/stevex/1301077,如需转载请自行联系原作者