背景
2021.6 在写一个生产者-消费者任务时,使用了LinkedBlockingQueue来同步数据。
一个生产者生产数据,多个消费者消费数据
现象:消费数据的线程有时出问题,生产的数据和消费的数据对不上
分析
猜测是线程安全问题,LinkedBlockingQueue这个集合的线程安全可能无法保证
尝试
- 网上查阅了资料,LinkedBlockingQueue是线程安全的,很奇怪
- 试用了ConcurrentLinkedQueue,问题暂时得到了解决
- 几天后查询LinkedBllockingQueue的api,发现poll方法是会返回null值的
- 原本程序中确实是用poll获取数据的
- 测试了一下,果然是queue为空时,某个线程获取到null,然后逻辑中报NPE导致的线程崩溃
- 这也是为啥日志中没有太多日志的原因
问题复现
public static void main(String[] args) {
Random random = new Random();
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>();
int i = 0;
while (i < 10) {
queue.offer(String.valueOf(i));
i++;
}
ExecutorService p1 = Executors.newCachedThreadPool();
ExecutorService p2 = Executors.newCachedThreadPool();
Thread x = new Thread(() -> {
ArrayList<String> strings = new ArrayList<>();
//这里的isEmpty()方法,是导致这个NPE的元凶
//
while (!queue.isEmpty()) {
strings.add(queue.poll());
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "--" + strings.size());
//注意:这里可能会报空指针问题
for (String string : strings) {
System.out.println(string.toLowerCase());
}
});
p1.submit(x);
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
p2.submit(x);
}
总结
线程