背景

2021.6 在写一个生产者-消费者任务时,使用了LinkedBlockingQueue来同步数据。
一个生产者生产数据,多个消费者消费数据

现象:消费数据的线程有时出问题,生产的数据和消费的数据对不上

分析

猜测是线程安全问题,LinkedBlockingQueue这个集合的线程安全可能无法保证

尝试

  • 网上查阅了资料,LinkedBlockingQueue是线程安全的,很奇怪
  • 试用了ConcurrentLinkedQueue,问题暂时得到了解决
  • 几天后查询LinkedBllockingQueue的api,发现poll方法是会返回null值的
  • 原本程序中确实是用poll获取数据的
  • 测试了一下,果然是queue为空时,某个线程获取到null,然后逻辑中报NPE导致的线程崩溃
  • 这也是为啥日志中没有太多日志的原因

问题复现

  1. public static void main(String[] args) {
  2. Random random = new Random();
  3. LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>();
  4. int i = 0;
  5. while (i < 10) {
  6. queue.offer(String.valueOf(i));
  7. i++;
  8. }
  9. ExecutorService p1 = Executors.newCachedThreadPool();
  10. ExecutorService p2 = Executors.newCachedThreadPool();
  11. Thread x = new Thread(() -> {
  12. ArrayList<String> strings = new ArrayList<>();
  13. //这里的isEmpty()方法,是导致这个NPE的元凶
  14. //
  15. while (!queue.isEmpty()) {
  16. strings.add(queue.poll());
  17. try {
  18. Thread.sleep(500);
  19. } catch (Exception e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. System.out.println(Thread.currentThread().getName() + "--" + strings.size());
  24. //注意:这里可能会报空指针问题
  25. for (String string : strings) {
  26. System.out.println(string.toLowerCase());
  27. }
  28. });
  29. p1.submit(x);
  30. try {
  31. Thread.sleep(500);
  32. } catch (Exception e) {
  33. e.printStackTrace();
  34. }
  35. p2.submit(x);
  36. }

总结

线程