概述
用idea debug功能演示上一篇博客中提到的
本实现中的出队、入队的实现逻辑会不会有线程安全问题?如果有,怎么解决?
测试用例
package com.lovehena.datastructure.test;
import com.lovehena.datastructure.ArrayQueue;
/*
* 测试 offer() poll()方法的线程安全问题
* */
public class TestArrayQueue2 {
/**
* 测试 offer() 方法的线程安全问题
* @param args
*/
public static void main(String[] args) throws InterruptedException {
ArrayQueue queue = new ArrayQueue(3);
/**
* 预期是 线程1将1入队 线程2将2入队
* 但由于可能发生指令交错 导致线程安全问题 则可能的结果是 队列中只有2 或者 只有1
* 用idea debug功能模拟
*/
Thread t1 = new Thread(() -> {
queue.offer(1);
}, "t1");
Thread t2 = new Thread(() -> {
queue.offer(2);
}, "t2");
t1.start();
t2.start();
// 等待t1、t2线程执行完毕
t1.join();
t2.join();
// 打印得到的queue
queue.print();
}
}
演示
文字不好叙述,录制了一个视频。
测试用例输出
元素2将元素1覆盖的情形
元素1将元素2覆盖的情形
解决线程安全问题
常见思路就是加锁。
我这个不涉及集群部署,所以用synchronized、lock(java.util.concurrent.locks.Lock)实现即可。
代码示例
// 多个线程往同一队列中入队元素时,确保锁是同一个。
// 一般将锁对象设置为队列的一个成员变量
private ReentrantLock lock=new ReentrantLock(); // 控制offer的锁
public boolean offer(int value) {
lock.lock(); // 加锁成功后 以下代码才会被执行
try {
if (tail == capacity) { //队列放满了
log.info("元素 {} 入队失败 因为队列放满了", value);
return false;
}
arr[tail] = value;
tail++;
}finally {
lock.unlock(); // 一定要记得手动释放锁 否则导致其他线程无法获取到锁 进而无法入队元素
}
return true;
}
以上代码经测试,不会再有线程安全问题。
扩展
测试poll()方法的线程安全问题。
加锁解决poll()方法的线程安全问题。
最后
好了,如果对你有帮助的话,欢迎点个免费的赞哦。