文章目录
Java对并发编程的支持历史
【并发编程】Java对并发编程的支持历史
参考URL: https://www.cnblogs.com/54chensongxia/p/11935356.html
JDK1.4及之前
在JDK1.4及之前的版本,主要提供的并发技术有:
- synchronized关键字
- volatile关键字
- 不变模式
所谓不变模式,就是指:在并发编程中,为确保数据的一致性和正确性,使用一种不可改变的对象。依靠其不可变的性质,来确保在没有同步的情况下依旧保持一致性和正确性。
Java中不变模式相关技术有:
- final关键字
- String类型
JDK1.5
JDK5是Java发展的一个重要版本,提供了很多技术,如泛型 Generic、枚举类型 Enumeration、可变参数varargs、注解 Annotations等等。
在JDK1.5版本中,也提供了对并发编程极为重要的一个包:java.util.concurrent(并发包)
java.util.concurrent(并发包)提供了一些列较为给力的并发技术,主要有:
-
原子(Atomic)类型:如AtomicInteger、AtomicReference等,保证变量的原子性和可见性。
-
显式锁(Lock)接口:对之前版本锁机制的重构,相较于synchronized 关键字,能够提供更加灵活的特性,如:能够指定锁定公平性、可以实现分组唤醒(Condition)、性能更好的锁。主要包括:Lock接口、ReadWriteLock接口和Condition接口。
-
计数器(CountDownLatch):利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行。
CountDownLatch的字面意思:倒计时 门栓。它的功能是:让一些线程阻塞直到另一些线程完成一系列操作后才唤醒。它通过调用await方法让线程进入阻塞状态等待倒计时0时唤醒。它通过线程调用countDown方法让倒计时中的计数器减去1,当计数器为0时,会唤醒哪些因为调用了await而阻塞的线程。
-
回环栅栏(CyclicBarrier):通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。
CyclicBarrier [ˈsaɪklɪk] [ˈbæriər] 的字面意思:可循环使用的屏障 【栅栏】。它的功能是:让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障,所有被屏障拦截的线程才会继续执行。它通过调用await方法让线程进入屏障。
-
信号量(Semaphore):Semaphore可以控同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。
-
并发集合:即集合类在并发环境下的版本。主要有:BlockingQueue(Queue)、ConcurrentMap(Map)、ConcurrentHashMap(HashMap)、CopyOnWriteArrayList(ArrayList)。
-
Callable和Future接口:为了解决继承Thread类和实现Runnable接口存在的弊端(不允许声明检查型异常,不能定义返回值),而引入的线程的新的定义方式。
-
执行器(Executor接口):Executors相关类隐藏了如何处理Runnable的细节,提供了一组方法,能够创建拥有完善配置的线程池和executor。
JDK1.7
在JDK1.7版本中,主要提供的并发编程技术有:
- TransferQueue:比BlockingQueue性能更好的并发集合实现。
- 分支合并(Fork/Join)框架:运用分治法(divide-and-conquer)的思想,实现线程池中任务的自动调度,并且这种调度对用户来说是透明的,典型应用ForkJoinPool。
Java 7中的TransferQueue
Java 7中的TransferQueue
参考URL: http://ifeve.com/java-transfer-queue/
TransferQueue实例
参考URL: https://segmentfault.com/a/1190000011266361
Java7中加入了JSR 166y规范对集合类和并发类库的改进。其中的一项是增加了接口TransferQueue和其实现类LinkedTransferQueue。
TransferQueue继承了BlockingQueue(BlockingQueue又继承了Queue)并扩展了一些新方法。BlockingQueue(和Queue)是Java 5中加入的接口,它是指这样的一个队列:当生产者向队列添加元素但队列已满时,生产者会被阻塞;当消费者从队列移除元素但队列为空时,消费者会被阻塞。
TransferQueue则更进一步,生产者会一直阻塞直到所添加到队列的元素被某一个消费者所消费(不仅仅是添加到队列里就完事)。新添加的transfer方法用来实现这种约束。顾名思义,阻塞就是发生在元素从一个线程transfer到另一个线程的过程中,它有效地实现了元素在线程之间的传递(以建立Java内存模型中的happens-before关系的方式)。
TransferQueue还包括了其他的一些方法:两个tryTransfer方法,一个是非阻塞的,另一个带有timeout参数设置超时时间的。还有两个辅助方法hasWaitingConsumer()和getWaitingConsumerCount()。
在队列中已有元素的情况下,调用transfer方法,可以确保队列中被传递元素之前的所有元素都能被处理。
使用场景:
当我们不想生产者过度生产消息时,TransferQueue可能非常有用,可避免发生 OOM错误。在这样的设计中,消费者的消费能力将决定生产者产生消息的速度。
ForkJoin
java.util.concurrent.ForkJoinPool由Java大师Doug Lea主持编写,它可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出。
JDK1.8
JDK1.8
- 加法器(Adder)和累加器(Accumulator):原子类型的扩充与优化,主要有:LongAdder、LongAccumulator、DoubleAdder和DoubleAccumulator,比AtomicLong和AtomicDouble性能更优。
- CompletableFuture:JDK5中Future的增强版。
- StampedLock:JDK5中ReadWriteLock的改进版。
java.util.concurrent.ForkJoinPool由Java大师Doug Lea主持编写,它可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出。
LongAccumulator
比LongAddr功能更强大的LongAccumulator原子类原理探究
参考URL: https://cloud.tencent.com/developer/article/1466107
Accumulator
英 [əˈkjuːmjəleɪtə®] 美 [əˈkjuːmjəleɪtər]
多重彩;累加器;累计期权;蓄能器;累积器
JDK8中新增原子性操作类LongAccumulator。LongAdder类时LongAccumulator的一个特例,只是后者提供了更强大的功能,让用户自定义累加规则。它常用于状态采集、统计等场景。
LongAddr与LongAccumulator类都是使用非阻塞算法CAS实现的,这相比于使用锁实现原子性操作在性能上有很大的提高。
LongAddr类是LongAccumulator类的一个特例,只是LongAccumulator提供了更强大的功能,可以让用户自定义累加规则。
CompletableFuture
使用CompletableFuture
参考URL: https://www.liaoxuefeng.com/wiki/1252599548343744/1306581182447650
这个completableFuture是JDK1.8版本新引入的类。
使用Future获得异步执行结果时,要么调用阻塞方法get(),要么轮询看isDone()是否为true,这两种方法都不是很好,因为主线程也会被迫等待。
从Java 8开始引入了CompletableFuture,它针对Future做了改进,可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法。
StampedLock
一个带有邮戳的锁StampedLock(jdk1.8引入)
参考URL: https://baijiahao.baidu.com/s?id=1649614767637994792&wfr=spider&for=pc
StampedLock
参考URL: https://www.jianshu.com/p/a35597e7c221
Java1.8引入了一个新锁StampedLock,这个锁可以认为是ReadWriteLock的改进。
ReadWriteLock中写和读是互斥的,也就是如果有一个线程在写共享变量的话,其他线程读共享变量都会阻塞。
StampedLock把读分为了悲观读和乐观读,悲观读就等价于ReadWriteLock的读,而乐观读在一个线程写共享变量时,不会被阻塞,乐观读是不加锁的。所以没锁肯定是比有锁的性能好,这样的话在大并发读情况下效率就更高了!
StampedLock的用法稍稍有点不同,在获取锁和乐观读时,都会返回一个stamp,解锁时需要传入这个stamp,在乐观读时是用来验证共享变量是否被其他线程写过。
CountDownlatch和CyclicBarrier以及Semaphor的区别是
CountDownLatch和CylicBarrier以及Semaphare你使用过吗
参考URL: https://www.cnblogs.com/wangsen/p/11170709.html
-
CountDownLatch是做减法,CyclicBarrier是做加法, Semaphor的临界资源可以反复使用
-
CountDownLatch不能重置计数,CycliBarrier提供的reset()方法可以重置计数,不过只能等到第一个计数结束。Semaphor可以重复使用。
-
CountDownLatch和CycliBarrier不能控制并发线程的数量,Semaphor可以实现控制并发线程的数量。
参考
CountDownLatch和CylicBarrier以及Semaphare你使用过吗
参考URL: https://www.cnblogs.com/wangsen/p/11170709.html
本文回顾了Java并发编程的历史,从JDK1.4到JDK1.8,介绍了synchronized、volatile、原子类型、显式锁、并发集合、Fork/Join框架、CompletableFuture等关键技术的发展。
165

被折叠的 条评论
为什么被折叠?



