Lock应用之 尝试锁获取

简介:

当线程请求内部锁时,如果锁已经被占用,则请求线程必须无条件等待,这往往会造成很多奇怪问题,相互等待是造成死锁的重要原因之一,著名的哲学家就餐问题就是个典型的案例。新的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,如需转载请自行联系原作者






相关文章
|
Java 程序员 API
【Lock锁的使用与原理】
【Lock锁的使用与原理】
177 0
|
数据可视化 Java
lock锁和死锁
lock锁和死锁
|
SQL 关系型数据库 MySQL
数据库并发控制、悲观锁(Pessimistic Lock)、乐观锁(Optimistic Lock)、排他锁(Exclusivelocks X锁)、共享锁(Shared Lock S锁)
数据库并发控制、悲观锁(Pessimistic Lock)、乐观锁(Optimistic Lock)、排他锁(Exclusivelocks X锁)、共享锁(Shared Lock S锁)
数据库并发控制、悲观锁(Pessimistic Lock)、乐观锁(Optimistic Lock)、排他锁(Exclusivelocks X锁)、共享锁(Shared Lock S锁)
|
安全 Java
多线程详解p18、Lock锁
多线程详解p18、Lock锁
|
安全 Java
Lock 解析,如何避免死锁?
Lock 解析,如何避免死锁?
Lock 解析,如何避免死锁?
|
API 数据安全/隐私保护
Lock锁
Lock锁
146 0
Lock锁
|
安全 Java 调度
多线程同步问题,锁Lock,synchronized
线程同步机制 并发:同一个对象被多个线程同时操作 处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象。这时候我们就需要线程同步。线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下一个县城再使用 线程同步形成条件:队列+
|
Java
多线程--Lock锁
多线程--Lock锁
249 0
多线程--Lock锁
深入学习Lock锁(3)——重入锁ReentrantLock
参考资料《Java并发编程的艺术》
1422 0