ReentrantLock
功能概述
- 可重入锁,类似于管程。
- 改进及优势:可被打断,可设定超时,可尝试拿锁,可设置多个条件队列。
方法介绍:
image.png- 构造方法:重入,非重入
- lock :抢锁,抢到继续,抢不到阻塞
- tryLock() :尝试抢锁,立即返回抢锁结果
- tryLock(long,TimeUnit) :尝试抢锁,限时等待
- lockInterruptibly :比lock 多了 可打断支持
- isLocked :是判断锁的状态,可用作监控使用。
- 其他一些状态判断,结果是评估值
设计:
- 锁状态:0无锁,n,同一个线程重入加锁了n次,n>=1。
- 拿不到锁,会排队,可获取当前持锁的线程,排队中的线程总数
- 公平、非公平(默认)抢锁,非公平 线程使用效率更高。
-
多个条件变量(Condition)用于线程之间的协作。
image.png
公平vs 非公平
- 公平锁:
- 空队列则抢占
- 队列不为空就排队
- 释放锁后,队首线程抢占锁。
- 非公平:
- 空队列则抢占
- 不管是否有排队线程,只要当是无线程持有锁,就抢占用
- 抢占不成功就排队。
Demo
package com.rock.multithread.juc.lock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo {
public static void main(String[] args) throws InterruptedException {
//lockNomal();
//tryLock();
lockInterruptibly1();
//lockInterruptibly2();
//tryLockTimeout
}
public static void lockNomal(){
ReentrantLock reentrantLock = new ReentrantLock();
reentrantLock.lock();
try {
//do something
}finally {
reentrantLock.unlock();
}
}
public static void tryLock() throws InterruptedException {
ReentrantLock reentrantLock = new ReentrantLock();
//线程1拿到锁不释放
Thread thread1 = new Thread(()->{
reentrantLock.lock();
//当前线程的重入次数。
System.out.println("thread1:" + reentrantLock.getHoldCount());
reentrantLock.lock();
System.out.println("thread1:" + reentrantLock.getHoldCount());
});
thread1.start();
TimeUnit.SECONDS.sleep(1);
Thread thread2= new Thread(()->{
boolean bLocked = reentrantLock.tryLock();
//boolean bLocked = reentrantLock.tryLock(5,TimeUnit.SECONDS);
if(bLocked){
try {
//do something
}finally {
reentrantLock.unlock();
}
}else{
System.out.println(reentrantLock.getQueueLength());
System.out.println(reentrantLock.hasQueuedThreads());
System.out.println(reentrantLock.isLocked());
System.out.println(reentrantLock.hasQueuedThread(thread1));
System.out.println(reentrantLock.getHoldCount());
}
});
thread2.start();
TimeUnit.SECONDS.sleep(5);
thread2.interrupt();
System.out.println("end");
}
/**
* 被中断时,没有拿到所以,unlock会报错
* @throws InterruptedException
*/
public static void lockInterruptibly1() throws InterruptedException {
ReentrantLock reentrantLock = new ReentrantLock();
//线程1拿到锁不释放
Thread thread1 = new Thread(()->{
reentrantLock.lock();
});
thread1.start();
TimeUnit.SECONDS.sleep(1);
Thread thread2= new Thread(()->{
try {
reentrantLock.lockInterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
try {
//被中断时,没有拿到所以,unlock会报错
reentrantLock.unlock();
}catch (Exception exp){
exp.printStackTrace();
}
}
});
thread2.start();
TimeUnit.SECONDS.sleep(1);
thread2.interrupt();
System.out.println("end");
}
/**
* lockInterruptibly 对中断的处理:
* 1. 中断异常直接外抛
* 2. catch掉,要控制后续逻辑
* @throws InterruptedException
*/
public static void lockInterruptibly2() throws InterruptedException {
ReentrantLock reentrantLock = new ReentrantLock();
//线程1拿到锁不释放
Thread thread1 = new Thread(()->{
reentrantLock.lock();
});
thread1.start();
TimeUnit.SECONDS.sleep(1);
Thread thread2= new Thread(()->{
boolean bLocked = true;
try {
reentrantLock.lockInterruptibly();
} catch (InterruptedException e) {
bLocked = false;
//异常直接抛出
}
if(bLocked){
try {
//do something
}finally {
reentrantLock.unlock();
}
}
});
thread2.start();
TimeUnit.SECONDS.sleep(5);
thread2.interrupt();
System.out.println("end");
}
/**
* 带超时的tryLock()
* @throws InterruptedException
*/
public static void tryLockTimeout() throws InterruptedException {
ReentrantLock reentrantLock = new ReentrantLock();
//线程1拿到锁不释放
Thread thread1 = new Thread(()->{
reentrantLock.lock();
});
thread1.start();
TimeUnit.SECONDS.sleep(1);
Thread thread2= new Thread(()->{
boolean bLocked = true;
try {
bLocked = reentrantLock.tryLock(5,TimeUnit.SECONDS);
} catch (InterruptedException e) {
bLocked = false;
//异常直接抛出
}
if(bLocked){
try {
//do something
}finally {
reentrantLock.unlock();
}
}
});
thread2.start();
TimeUnit.SECONDS.sleep(5);
thread2.interrupt();
System.out.println("end");
}
}
网友评论