Java并发学习4【面试+工作】

Java并发学习4【面试+工作】

九.fork&join

Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。

  我们再通过Fork和Join这两个单词来理解下Fork/Join框架,Fork就是把一个大任务切分为若干子任务并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结果。比如计算1+2+。。+10000,可以分割成10个子任务,每个子任务分别对1000个数进行求和,最终汇总这10个子任务的结果。Fork/Join的运行流程图如下:

  我们已经很清楚Fork/Join框架的需求了,那么我们可以思考一下,如果让我们来设计一个Fork/Join框架,该如何设计?这个思考有助于你理解Fork/Join框架的设计。

  第一步分割任务。首先我们需要有一个fork类来把大任务分割成子任务,有可能子任务还是很大,所以还需要不停的分割,直到分割出的子任务足够小。

  第二步执行任务并合并结果。分割的子任务分别放在双端队列里,然后几个启动线程分别从双端队列里获取任务执行。子任务执行完的结果都统一放在一个队列里,启动一个线程从队列里拿数据,然后合并这些数据。

Fork/Join使用两个类来完成以上两件事情:

ForkJoinTask:我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。它提供在任务中执行fork()和join()操作的机制,通常情况下我们不需要直接继承ForkJoinTask类,而只需要继承它的子类,Fork/Join框架提供了以下两个子类: RecursiveAction:用于没有返回结果的任务。 RecursiveTask :用于有返回结果的任务。 ForkJoinPool :ForkJoinTask需要通过ForkJoinPool来执行,任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。当一个工作线程的队列里暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任务。

例子


十.jdk并发容器

同步容器

同步容器可以简单地理解为通过synchronized来实现同步的容器,如果有多个线程调用同步容器的方法,它们将会串行执行。

同步容器将它们的状态封装起来,并对每一个公有方法进行同步。主要包括:

  • Vector
  • Stack
  • HashTable
  • Collections.synchronized方法生成,例如: Collectinons.synchronizedList() Collections.synchronizedSet() Collections.synchronizedMap() Collections.synchronizedSortedSet() Collections.synchronizedSortedMap() 其中Vector(同步的ArrayList)和Stack(继承自Vector,先进后出)、HashTable(继承自Dictionary,实现了Map接口)是比较老的容器,Thinking in Java中明确指出,这些容器现在仍然存在于JDK中是为了向以前老版本的程序兼容,在新的程序中不应该在使用。Collections的方法时将非同步的容器包裹生成对应的同步容器。

同步容器在单线程的环境下能够保证线程安全,但是通过synchronized同步方法将访问操作串行化,导致并发环境下效率低下。而且同步容器在多线程环境下的复合操作(迭代、条件运算如没有则添加等)是非线程安全,需要客户端代码来实现加锁。

并发容器

由上面的分析我们知道,同步容器并不能保证多线程安全,而并发容器是针对多个线程并发访问而设计的,在jdk5.0引入了concurrent包,其中提供了很多并发容器,极大的提升同步容器类的性能。

ConcurrentHashMap

对应的非并发容器:HashMap 目标:代替Hashtable、synchronizedMap,支持复合操作 原理:JDK6中采用一种更加细粒度的加锁机制Segment“分段锁”,JDK8中采用CAS无锁算法

CopyOnWriteArrayList

对应的非并发容器:ArrayList 目标:代替Vector、synchronizedList 原理:利用高并发往往是读多写少的特性,对读操作不加锁,对写操作,先复制一份新的集合,在新的集合上面修改,然后将新集合赋值给旧的引用,并通过volatile 保证其可见性,当然写操作的锁是必不可少的了。

CopyOnWriteArraySet

对应的费并发容器:HashSet 目标:代替synchronizedSet 原理:基于CopyOnWriteArrayList实现,其唯一的不同是在add时调用的是CopyOnWriteArrayList的addIfAbsent方法,其遍历当前Object数组,如Object数组中已有了当前元素,则直接返回,如果没有则放入Object数组的尾部,并返回。

ConcurrentSkipListMap

对应的非并发容器:TreeMap 目标:代替synchronizedSortedMap(TreeMap) 原理:Skip list(跳表)是一种可以代替平衡树的数据结构,默认是按照Key值升序的。Skip list让已排序的数据分布在多层链表中,以0-1随机数决定一个数据的向上攀升与否,通过”空间来换取时间”的一个算法。ConcurrentSkipListMap提供了一种线程安全的并发访问的排序映射表。内部是SkipList(跳表)结构实现,在理论上能够在O(log(n))时间内完成查找、插入、删除操作。

ConcurrentSkipListSet

对应的非并发容器:TreeSet 目标:代替synchronizedSortedSet 原理:内部基于ConcurrentSkipListMap实现

ConcurrentLinkedQueue

不会阻塞的队列

对应的非并发容器:Queue 原理:基于链表实现的FIFO队列(LinkedList的并发版本)

BlockingQueue:数据共享通道

比如,线程A希望线程B发一个消息,用什么方式告知线程B比较合理的呢?用BlockingQueue最为合理。

BlockingQueue是一个接口,并非一个具体的实现。 BlockingQueue之所以适合做数据共享的通道,其关键还在于Blocking上。Blocking是阻塞的意思,当服务线程(服务线程指不断获取队列中的消息,进行处理的线程)处理完成队列中的消息后,他如何得知下一条消息何时到来呢?一种傻瓜式的方案是让这个线程按照一定的时间间隔不停的循环和监控这个队列。这是可行的一种方案,但显然造成了不必要的资源浪费,而循环周期也难以确定。而BlockingQueue很好的解决了这一个问题。它会让服务线程在队列为空是时,进行等待,当有新的消息进入队列后,自动将线程唤醒。

特点:拓展了Queue,增加了可阻塞的插入和获取等操作 原理:通过ReentrantLock实现线程安全,通过Condition实现阻塞和唤醒 实现类: LinkedBlockingQueue:基于链表实现的可阻塞的FIFO队列 ArrayBlockingQueue:基于数组实现的可阻塞的FIFO队列 PriorityBlockingQueue:按优先级排序的队列

本文分享自微信公众号 - Java帮帮(javahelp),作者:奋斗蒙

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-05-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 30个精简代码的小技巧

    优化代码,一个很重要的课题。可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对代码的运行效率有什么影响呢?这个问题我是真么考虑的,好比人吃饭,吃一粒米...

    Java帮帮
  • String中的null,以及String s;等区别详解

    1、判断一个引用类型数据是否null。 用==来判断。 2、释放内存,让一个非null的引用类型变量指向null。这样这个对象就不再被任何对象应用了。等待JVM...

    Java帮帮
  • Apache、struts1、struts2文件上传下载的3种方式

    /*jsp的上传(导入第三方upload.jar)*/ //用Apache的SmartUpload方式上传,共5部 //1.引入SmartUpload Smar...

    Java帮帮
  • Java的ThreadLocal

    ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状...

    用户3467126
  • JS中的事件循环机制与宏队列、微队列笔记

    为什么JavaScript是一门单线程语言?作为一门浏览器脚本语言,它的主要用途就是操作DOM和与用户交互设计,如果说js是多线程的话,那么它在操作DOM的时候...

    帅的一麻皮
  • MySQL的DML和DQL   增删改查

    DML和DQL   增删改查 SELECT * FROM grade --新增 insert -- 向年级表中新增3条数据 INSERT INTO grade...

    房上的猫
  • Core官方DI解析(3)-ServiceCallSite

    上一篇说过在整个DI框架中IServiceProviderEngine是核心,但是如果直接看IServiceProviderEngine派生类其实看不出也没什么...

    莫问今朝
  • Core官方DI解析(3)-ServiceCallSite.md

    上一篇说过在整个DI框架中IServiceProviderEngine是核心,但是如果直接看IServiceProviderEngine派生类其实看不出也没什么...

    莫问今朝
  • 队列的动态链式存储实现—C语言

    汐楓
  • nginx SYN flooding解决思路

    lf-weather-nginx-101-11:~ # tail -f /var/log/messages

    乡村小男孩

扫码关注云+社区

领取腾讯云代金券