阻塞队列-单锁实现-阻塞线程2
使用ReentrantLock
和Condition
来实现一个简单的线程安全的队列。以下是代码的详细解释
代码:
/*
1. synchronized 关键字, 功能少
2. ReentrantLock 可重入锁, 功能多
*/
public class TestThreadUnsafe {
private final String[] array = new String[10];
private int tail = 0;
private int size = 0;
ReentrantLock lock = new ReentrantLock(); // 锁对象
Condition tailWaits = lock.newCondition(); // 条件变量对象 集合
public void offer(String e) throws InterruptedException {
lock.lockInterruptibly(); // 加锁(可以在阻塞状态随时打断)
try {
if(isFull()) {
// 满了该做的事, offer 线程阻塞
tailWaits.await(); // 当前线程加入 tailWaits, 并且让此线程阻塞 tailWaits.signal()
}
array[tail] = e;
if(++tail == array.length) {
tail = 0;
}
size++;
} finally {
lock.unlock(); // 解锁
}
}
private boolean isFull() {
return size == array.length;
}
@Override
public String toString() {
return Arrays.toString(array);
}
public static void main(String[] args) throws InterruptedException {
TestThreadUnsafe queue = new TestThreadUnsafe();
for (int i = 0; i < 10; i++) {
queue.offer("e" + i);
}
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName() + "添加元素之前");
queue.offer("e10");
System.out.println(Thread.currentThread().getName() + "添加元素成功");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, "t1").start();
new Thread(()->{
System.out.println("开始唤醒");
try {
queue.lock.lockInterruptibly();
queue.tailWaits.signal();
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
finally {
queue.lock.unlock();
}
}, "t2").start();
}
}
断点分析:
我们进行断点查看:
将断掉标记到 74行代码处
当轮到 线程2 执行时 线程 1 是被 阻塞了
所以控制台打印了
Connected to the target VM, address: '127.0.0.1:11310', transport: 'socket'
t1添加元素之前
然后 我们在 线程2 处打了断点 所以 我们直接往下执行程序,打印如下:
Connected to the target VM, address: '127.0.0.1:11310', transport: 'socket'
t1添加元素之前
开始唤醒
走到下图这个位置的时候 线程 2 拿到锁
PS:线程 1 拿到锁的时候 由于 wait() 函数 将 线程 1 阻塞了 会 主动的 释放锁
再往下执行的时候 释放了 tailWaits 中 的锁 进行 对 Condition 里面的阻塞 线程的唤醒
PS:这里只是下达了这样的指令 并没有 真正的 唤醒 线程 1 需要 释放锁后 才会 真正唤醒 线程 1
然后再往下执行 线程 2 释放锁
PS:当线程 2 释放锁后 才会 唤醒 线程 1 此时 线程 1 被唤醒 然后 接着 上次的 isFull 往下执行程序
线程 2 释放完成后 ,线程 1 往下执行 完毕 此时 e0 的地方就会被赋值为 e10了
文档信息
- 本文作者:Dkx
- 本文链接:https://pigpigletsgo.github.io/dou_note.github.io/2024/03/07/zuseduiliedansuoshixiantwo/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)