一、ReentrantLock是什么
ReentrantLock是一个互斥的可重入锁。互斥的意思就是排他,独占,只能一个线程获取到锁。可重入的意思就是单个线程可以多次重复获取锁。
二、ReentrantLock常用方法
方法名 | 说明 | 抛出异常 |
---|---|---|
lock() | 一直阻塞获取锁,直到获取成功 | 无 |
lockInterruptibly() | 尝试获取锁,直到获取锁或者线程被中断 | InterruptedException |
tryLock() | 尝试获取空闲的锁,获取成功返回true,获取失败返回false,不会阻塞,立即返回 | 无 |
tryLock(long time, TimeUnit unit) | 尝试在time时间内获取空闲的锁,在等待时间内可以被中断 | InterruptedException |
unlock() | 释放锁 | 无 |
newCondition() | 返回当前锁的一个condition实例,用于条件性等待 | 无 |
三、ReentrantLock与synchronized
ReentrantLock与 synchronized功能其实差不多,都是可重入锁。synchronized自动释放锁,需要通过unlock()手动释放锁。ReentrantLock但ReentrantLock功能更强大一点,可以响应中断,另外配合condition可以等待/唤醒特定的线程。
四、Condition
Condition用来使线程等待或者唤醒线程,唤醒的线程是使用同一个condition等待的线程,所以可以唤醒特定的线程。
四、代码示例
/**
* <h1>仓库类</h1>
*/
public class Depot {
private int capacity; // 仓库的容量
private int size; // 仓库的实际数量
private Lock lock; // 独占锁
private Condition fullCondtion; // 生产条件
private Condition emptyCondtion; // 消费条件
/**
* 初始化
*/
public Depot() {
capacity = 100;
size = 0;
lock = new ReentrantLock();
fullCondtion = lock.newCondition();
emptyCondtion = lock.newCondition();
}
/**
* <h2>生产流程</h2>
*
* @param val:生产的个数
*/
public void produce(int val) {
try {
lock.lock();
System.out.println("生产者:" + Thread.currentThread().getName() + "开始执行");
//left:还需生产的个数
int left = val;
while (left > 0) {
//当仓库满了,需要暂停生产
if (size >= capacity) {
System.out.println(Thread.currentThread().getName() + ":当前仓库已满,生产进程进入等待");
//当前生产进程阻塞
fullCondtion.await();
}
// incr:此次生产的数量
int incr = (capacity - size) > left ? left : (capacity - size);
size = size + incr;
left = left - incr;
System.out.println(Thread.currentThread().getName() + "生产:incr=" + incr + ",left=" + left + ",size=" + size);
// 生产完了,唤起消费进程
emptyCondtion.signal();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
}
/**
* <h2>消费流程</h2>
*
* @param val:消费的个数
*/
public void consume(int val) {
try {
lock.lock();
System.out.println("消费者:" + Thread.currentThread().getName() + "开始执行");
//left:剩余消费的数量
int left = val;
while (left > 0) {
if (size <= 0) {
System.out.println(Thread.currentThread().getName() + ":当前仓库已空,消费进程进入等待");
emptyCondtion.await();
}
// dec : 此次消费的个数
int dec = size > left ? left : size;
left = left - dec;
size = size - dec;
System.out.println(Thread.currentThread().getName() + "消费:dec=" + dec + ",left=" + left + ",size=" + size);
// 唤醒生产进程
fullCondtion.signal();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
生产者:
/**
* <h1>生产者</h1>
*/
public class Producer {
private Depot depot;
public Producer(Depot depot){
this.depot= depot;
}
public void produce(int val){
new Thread(){
@Override
public void run() {
depot.produce(val);
}
}.start();
}
}
消费者:
/**
* <h1>消费者</h1>
*/
public class Consumer {
private Depot depot;
public Consumer(Depot depot){
this.depot = depot;
}
public void consume(int val){
new Thread(){
@Override
public void run() {
depot.consume(val);
}
}.start();
}
}
函数调用:
public static void main(String[] args) {
SpringApplication.run(RoadApplication.class, args);
Depot depot = new Depot();
Producer producer = new Producer(depot);
Consumer consumer = new Consumer(depot);
consumer.consume(150);
producer.produce(200);
producer.produce(100);
consumer.consume(150);
consumer.consume(50);
producer.produce(200);
}
运行结果:
消费者:Thread-7开始执行
Thread-7:当前仓库已空,消费进程进入等待
生产者:Thread-8开始执行
Thread-8生产:incr=100,left=100,size=100
Thread-8:当前仓库已满,生产进程进入等待
生产者:Thread-9开始执行
Thread-9:当前仓库已满,生产进程进入等待
生产者:Thread-12开始执行
Thread-12:当前仓库已满,生产进程进入等待
Thread-7消费:dec=100,left=50,size=0
Thread-7:当前仓库已空,消费进程进入等待
消费者:Thread-10开始执行
Thread-10:当前仓库已空,消费进程进入等待
消费者:Thread-11开始执行
Thread-11:当前仓库已空,消费进程进入等待
Thread-8生产:incr=100,left=0,size=100
Thread-7消费:dec=50,left=0,size=50
Thread-9生产:incr=50,left=50,size=100
Thread-9:当前仓库已满,生产进程进入等待
Thread-10消费:dec=100,left=50,size=0
Thread-10:当前仓库已空,消费进程进入等待
Thread-12生产:incr=100,left=100,size=100
Thread-12:当前仓库已满,生产进程进入等待
Thread-11消费:dec=50,left=0,size=50
Thread-9生产:incr=50,left=0,size=100
Thread-10消费:dec=50,left=0,size=50
Thread-12生产:incr=50,left=50,size=100
Thread-12:当前仓库已满,生产进程进入等待
网友评论