likes
comments
collection
share

Java多线程(7):JUC(下)

作者站长头像
站长
· 阅读数 73

除了四种常见的同步器(发令枪、摇号器、栅栏和交换机),JUC还有所谓线程安全的容器、阻塞队列和一些特殊的类。其中常出现的就是线程安全的容器和阻塞队列。与其说这是两个大的分类,还不如说它就是两个用得最多的类:ConcurrentHashMap和ArrayBlockingQueue。

我的风格是尽量少讲原理,多讲实际生活中的案例,除非它非常重要,就像AQS,这玩意绝对是个重量级的神器,差不多整个JUC都是建立在它之上的。如果说学习多线程只有一次集中全部精力的机会的话,那我绝对建议把这份宝贵的精力花在AQS上,物超所值。至于搞明白ThreadPool底层原理、synchronized关键字原理,个人认为纯属浪费时间。因为即使弄明白了,那个机制你是改不了的,而AQS原理弄明白了,可以直接拿来用,自己玩出花来。

从之前的集合类继承结构图可以知道,ConcurrentHashMap继承自Map,实现了ConcurrentMap接口,它是线程安全的Map,侧重于放入或者获取的速度,而不在乎顺序。

因为现在的Java基本上都升级到了JDK1.8以上,有的甚至和官方保持同步,所以基本上很多JDK1.7及以下会出现的问题,在新的版本中都修复了,而且性能越来越好。所以只需要知道一点:在并发量比较高的环境中尽量使用ConcurrentHashMap就好了。不用弄明白为什么,因为不值得(JDK1.8的ConcurrentHashMap底层是用红黑树实现的,至于什么是红黑树,又得回头补一些基础,而且记住了也没啥用)。当然如果是为了应付面试,稍稍了解一下就好了。

ArrayBlockingQueue和LinkedBlockingQueue在之前的线程池ThreadPool中也提过,它们的共同点都是一边放一边拿,唯一的不同是一个是数量有限的,一个是数量无限的。

Java多线程(7):JUC(下)

 

之前拿上菜的案例演示了ArrayBlockingQueue,现在同样的案例再用LinkedBlockingQueue来实现:

/**
 * LinkedBlockingQueue测试
 *
 * @author 湘王
 */
public class LinkedBlockingQueueTester {
   public static BlockingQueue<String> queue = new LinkedBlockingQueue<String>(5);
   // 一个往里放
   class Producer implements Runnable {
      @Override
      public void run() {
         try {
            queue.offer("川菜");
            System.out.println(Thread.currentThread().getName() + " 厨师做好 川菜");
         } catch (Exception e) {
            e.printStackTrace();
         }
      }
   }
   // 一个往外拿
   class Consumer implements Runnable {
      @Override
      public void run() {
         try {
            String food = queue.poll();
            System.out.println(Thread.currentThread().getName() + " 客人消费 " + food);
         } catch (Exception e) {
            e.printStackTrace();
         }
      }
   }
   public static void main(String[] args) {
      // 和ArrayBlockingQueue不讲究顺序不同,LinkedBlockingQueue需要将生产的一方放在前面
      // 厨师做好菜
      for (int i = 0; i < 5; i++) {
         new Thread(new LinkedBlockingQueueTester().new Producer()).start();
      }
      // 客人等着菜
      for (int i = 0; i < 5; i++) {
         new Thread(new LinkedBlockingQueueTester().new Consumer()).start();
      }
   }
}

JUC中一些其他的类,例如ForkJoinPool,可以把任务分解成更小的任务,被分解出来任务会被继续分解成更小的任务,更形象地说法是“分形器”。而RecursiveTask是一种会返回结果的任务,它可以将自己分解成若干更小的任务,并将这些任务的执行结果合并到一个结果里。这两种用的不多。

整个JUC里面最重要的还是前面3种共6个Java类,掌握好AQS和这6个常见类,JUC基本就没啥问题了。

感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~

转载自:https://juejin.cn/post/7161045558797271047
评论
请登录