并发编程-concurrent指南-Lock-可重入锁(ReentrantLock)
可重入和不可重入的概念是这样的:当一个线程获得了当前实例的锁,并进入方法A,这个线程在没有释放这把锁的时候,能否再次进入方法A呢?
- 可重入锁:可以再次进入方法A,就是说在释放锁前此线程可以再次进入方法A(方法A递归)。
- 不可重入锁(自旋锁):不可以再次进入方法A,也就是说获得锁进入方法A是此线程在释放锁钱唯一的一次进入方法A。
,具体区别查看可重入锁和不可重入锁区别。
ReentrantLock,意思是“可重入锁”。ReentrantLock是唯一实现了Lock接口的类,并且ReentrantLock提供了更多的方法。下面通过一些实例看具体看一下如何使用ReentrantLock。
lock()的正确使用方法
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class MainLock { private Lock lock = new ReentrantLock(); public static void main(String[] args) { final MainLock mainLock = new MainLock(); new Thread(new Runnable() { @Override public void run() { mainLock.insert(Thread.currentThread()); } }).start(); new Thread(new Runnable() { @Override public void run() { mainLock.insert(Thread.currentThread()); } }).start(); } public void insert(Thread thread){ lock.lock();//获取锁 try{ System.out.println(thread.getName() + "获取锁"); for(int i=0;i<5;i++){ System.out.println("------------------------" + thread.getName() + ":"+i+"------------------------"); } }finally { System.out.println(thread.getName() + "释放锁"); lock.unlock();//释放锁 } } }
结果:
Thread-0获取锁 ------------------------Thread-0:0------------------------ ------------------------Thread-0:1------------------------ ------------------------Thread-0:2------------------------ ------------------------Thread-0:3------------------------ ------------------------Thread-0:4------------------------ Thread-0释放锁 Thread-1获取锁 ------------------------Thread-1:0------------------------ ------------------------Thread-1:1------------------------ ------------------------Thread-1:2------------------------ ------------------------Thread-1:3------------------------ ------------------------Thread-1:4------------------------ Thread-1释放锁
tryLock()的使用方法
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class MainTryLock { private Lock lock = new ReentrantLock(); public static void main(String[] args) { final MainTryLock mainTryLock = new MainTryLock(); new Thread(){ @Override public void run() { mainTryLock.insert(Thread.currentThread()); } }.start(); new Thread(){ @Override public void run() { mainTryLock.insert(Thread.currentThread()); } }.start(); } public void insert(Thread thread){ if(lock.tryLock()){ try{ System.out.println(thread.getName() + "获取锁"); for(int i=0;i<5;i++){ Thread.sleep(200); } }catch (Exception e){ e.printStackTrace(); }finally { System.out.println(thread.getName() + "释放锁"); lock.unlock();//释放锁 } }else{ System.out.println(thread.getName()+"未获取到锁"); } } }
结果:
Thread-0获取锁 Thread-1未获取到锁 Thread-0释放锁
lockInterruptibly()响应中断的使用方法:
import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class MainLockInterruptibl { private Lock lock = new ReentrantLock(); public static void main(String[] args) { MainLockInterruptibl test = new MainLockInterruptibl(); MyThread thread1 = new MyThread(test); MyThread thread2 = new MyThread(test); thread1.start(); thread2.start(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } thread2.interrupt(); } public void insert(Thread thread) throws InterruptedException{ lock.lockInterruptibly(); //注意,如果需要正确中断等待锁的线程,必须将获取锁放在外面,然后将InterruptedException抛出 try { System.out.println(thread.getName()+"得到了锁"); long startTime = System.currentTimeMillis(); for( int i=0;i<5;i++) { TimeUnit.SECONDS.sleep(2); } } catch (Exception e){ e.printStackTrace(); }finally { System.out.println(Thread.currentThread().getName()+"执行finally"); lock.unlock(); System.out.println(thread.getName()+"释放了锁"); } } static class MyThread extends Thread { private MainLockInterruptibl test = null; public MyThread(MainLockInterruptibl test) { this.test = test; } @Override public void run() { try { test.insert(Thread.currentThread()); } catch (InterruptedException e) { e.printStackTrace(); System.out.println(Thread.currentThread().getName()+"被中断"); } } } }
结果:
Thread-0得到了锁 java.lang.InterruptedException Thread-1被中断 at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222) at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335) at com.concurrent.MainLockInterruptibl.insert(MainLockInterruptibl.java:25) at com.concurrent.MainLockInterruptibl$MyThread.run(MainLockInterruptibl.java:48) Thread-0执行finally Thread-0释放了锁
源码地址:https://github.com/qjm201000/concurrent_reentrantLock.git