ReentrantLock是一个锁,相对于synchronized, 这个锁更灵活,可以灵活的加锁和解锁。
我们先看一个例子
public class ReenterLock implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
public static int count = 0;
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
lock.lock();
try{
count++;
}finally{
lock.unlock(); // 防止发生某些意外,锁没有释放掉,其他线程无法进入
}
}
}
public static void main(String[] args) throws InterruptedException {
ReenterLock rl = new ReenterLock();
Thread t1 = new Thread(rl);
Thread t2 = new Thread(rl);
t1.start();t2.start();
t1.join();t2.join();
System.out.println(count);
}
}
如果对一段代码加了两个锁,例如
lock.lock();
lock.lock();
在解锁的时候,要执行两次unlock(),
lock.unlock();
lock.unlock();
二、可中断
ReentrantLock还有一个特性,就是可中断,在加锁的同时可以响应中断,让我们看下面这个例子:
public class ReenterLockInterrupt extends Thread {
public static ReentrantLock reenlock1 = new ReentrantLock();
public static ReentrantLock reenlock2 = new ReentrantLock();
public int lock;
public ReenterLockInterrupt(int lock) {
this.lock = lock;
}
@Override
public void run() {
try {
if (lock == 1) {
reenlock1.lockInterruptibly(); // 可以被中断的lock
Thread.sleep(1000);
reenlock2.lockInterruptibly(); // 可以被中断的lock
} else {
reenlock2.lockInterruptibly(); // 可以被中断的lock
Thread.sleep(1000);
reenlock1.lockInterruptibly(); // 可以被中断的lock
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if(reenlock1.isHeldByCurrentThread()){
reenlock1.unlock();
}
if(reenlock2.isHeldByCurrentThread()){
reenlock2.unlock();
}
System.out.println(Thread.currentThread().getId() + ":线程退出");
}
}
public static void main(String[] args) throws InterruptedException {
ReenterLockInterrupt t1 = new ReenterLockInterrupt(1);
ReenterLockInterrupt t2 = new ReenterLockInterrupt(2);
t1.start();
t2.start();
Thread.sleep(1000);
//t1.interrupt();
}
}
当我们把//t1.interrupt(); 注释掉的时候,程序就会一直处在运行状态
控制台输入 $ jstack 54728
2018-09-12 15:31:00
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.172-b11 mixed mode):
"Attach Listener" #12 daemon prio=9 os_prio=31 tid=0x00007fcb12819000 nid=0x1407 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"DestroyJavaVM" #11 prio=5 os_prio=31 tid=0x00007fcb12818000 nid=0x1c03 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-1" #10 prio=5 os_prio=31 tid=0x00007fcb13067800 nid=0x4f03 waiting on condition [0x000070000175f000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007955f5808> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at cn.eric.thread.lock.reentrant.ReenterLockInterrupt.run(ReenterLockInterrupt.java:27)
"Thread-0" #9 prio=5 os_prio=31 tid=0x00007fcb12023800 nid=0x4d03 waiting on condition [0x000070000165c000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007955f5838> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at cn.eric.thread.lock.reentrant.ReenterLockInterrupt.run(ReenterLockInterrupt.java:23)
可以看到死锁发生在(ReenterLockInterrupt.java:23)这里。如果我们把最后一行的注释注释掉,程序就可以关闭了。当然这样进行线程的打扰还是比较简单的,大家有兴趣可以自己写检测线程死锁的方法
三、可限时
可限时也是一种避免死锁和长期等待的措施,主要方法 tryLock(5,TimeUnit.SECONDS)
public class ReenterLockTime implements Runnable {
public static ReentrantLock lock = new ReentrantLock();
public static int count = 0;
@Override
public void run() {
try {
if(lock.tryLock(5, TimeUnit.SECONDS)){
System.out.println(Thread.currentThread().getId() + "get lock success");
Thread.sleep(6000);
}else{
System.out.println(Thread.currentThread().getId() + "get lock failed");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
if(lock.isHeldByCurrentThread())
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ReenterLockTime rl = new ReenterLockTime();
Thread t1 = new Thread(rl);
Thread t2 = new Thread(rl);
t1.start();t2.start();
}
}
输出:
9get lock success
10get lock failed
四、公平锁
公平锁保证线程先来先得锁,后来后得锁
例子:
public class ReenterLockFair implements Runnable{ //创建公平锁 private static ReentrantLock lock=new ReentrantLock(true); public void run() { while(true){ lock.lock(); try{ System.out.println(Thread.currentThread().getName()+"线程得锁"); }finally{ lock.unlock(); } } } public static void main(String[] args) { ReenterLockFair rlf=new ReenterLockFair(); Thread t1=new Thread(rlf); Thread t2=new Thread(rlf); t1.start(); t2.start(); } }