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