JUC容器介绍

Java技术债务

共 3737字,需浏览 8分钟

 · 2022-03-12

JUC结构

13ab5256068890789726b1c3f9ba4b0b.webp

1. tools(工具类):又叫信号量三组工具类,包含有

1.CountDownLatch(倒计数) 是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待2.CyclicBarrier(循环栅栏) 之所以叫barrier,是因为是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 ,并且在释放等待线程后可以重用。3.Semaphore(信号量) 是一个计数信号量,它的本质是一个“共享锁“。信号量维护了一个信号量许可集。线程可以通过调用 acquire()来获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到有可用的许可为止。线程可以通过release()来释放它所持有的信号量许可。

2.executor(执行者):是Java里面线程池的顶级接口,但它只是一个执行线程的工具,真正的线程池接口是ExecutorService,里面包含的类有:

1.ScheduledExecutorService 解决那些需要任务重复执行的问题2.ScheduledThreadPoolExecutor 周期性任务调度的类实现

3.atomic(原子性包):是JDK提供的一组原子操作类,4.locks(锁包):是JDK提供的锁机制,相比synchronized关键字来进行同步锁,功能更加强大,它为锁提供了一个框架,该框架允许更灵活地使用锁包含的实现类有:

1.ReentrantLock 它是独占锁,是指只能被独自占领,即同一个时间点只能被一个线程锁获取到的锁。2.ReentrantReadWriteLock 它包括子类ReadLock和WriteLock。ReadLock是共享锁,而WriteLock是独占锁。3.LockSupport 它具备阻塞线程和解除阻塞线程的功能,并且不会引发死锁[1]

5.collections(集合类):主要是提供线程安全的集合, 比如:

1.ArrayList对应的高并发类是CopyOnWriteArrayList,2.HashSet对应的高并发类是 CopyOnWriteArraySet,3.HashMap对应的高并发类是ConcurrentHashMap等等



1、tools(工具类)

JUC 中的同步器三个主要的成员:CountDownLatch、CyclicBarrier 和 Semaphore,通过它们可以方便地实现很多线程之间协作的功能。

CountDownLatch

叫倒计数,允许一个或多个线程等待某些操作完成。

看几个场景:1、跑步比赛,裁判需要等到所有的运动员(“其他线程”)都跑到终点(达到目标),才能去算排名和颁奖。

2、模拟并发,我需要启动 100 个线程去同时访问某一个地址,我希望它们能同时并发,而不是一个一个的去执行。

用法:CountDownLatch 构造方法指明计数数量,被等待线程调用 countDown 将计数器减 1,等待线程使用 await 进行线程等待。d91b827a4c3d4434c37d1956c71c967d.webp

CyclicBarrier

叫循环栅栏,它实现让一组线程等待至某个状态之后再全部同时执行,而且当所有等待线程被释放后,CyclicBarrier 可以被重复使用。CyclicBarrier 的典型应用场景是用来等待并发线程结束。

CyclicBarrier 的主要方法是 await(),await() 每被调用一次,计数便会减少 1,并阻塞住当前线程。当计数减至 0 时,阻塞解除,所有在此 CyclicBarrier 上面阻塞的线程开始运行。在这之后,如果再次调用 await(),计数就又会变成 N-1,新一轮重新开始,这便是 Cyclic 的含义所在。CyclicBarrier.await() 带有返回值,用来表示当前线程是第几个到达这个 Barrier 的线程。beffc1e2a06c712214d7a5e0180b47ed.webp

Semaphore

Java 版本的信号量实现,用于控制同时访问的线程个数,来达到限制通用资源访问的目的,其原理是通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。

如果 Semaphore 的数值被初始化为 1,那么一个线程就可以通过 acquire 进入互斥状态,本质上和互斥锁是非常相似的。

但是区别也非常明显,比如互斥锁是有持有者的,而对于 Semaphore 这种计数器结构,虽然有类似功能,但其实不存在真正意义的持有者,除非我们进行扩展包装。e500e557c9589158ba528be686271958.webp

CyclicBarrier 和 CountDownLatch 区别

CountDownLatch 是不可以重置的,所以无法重用,CyclicBarrier 没有这种限制,可以重用。

CountDownLatch 的基本操作组合是 countDown/await,调用 await 的线程阻塞等待 countDown 足够的次数,不管你是在一个线程还是多个线程里 countDown,只要次数足够即可。CyclicBarrier 的基本操作组合就是 await,当所有的伙伴都调用了 await,才会继续进行任务,并自动进行重置。

CountDownLatch 目的是让一个线程等待其他 N 个线程达到某个条件后,自己再去做某个事(通过 CyclicBarrier 的第二个构造方法 public CyclicBarrier(int parties, Runnable barrierAction),在新线程里做事可以达到同样的效果)。

而 CyclicBarrier 的目的是让 N 多线程互相等待直到所有的都达到某个状态,然后这 N 个线程再继续执行各自后续(通过 CountDownLatch 在某些场合也能完成类似的效果)。

2、executor

关于线程池更多更详细的请看之前的文章:

Java创建线程池的方式[2]

线程池的理解以及使用[3]

3、atomic

包含有AtomicBoolean、AtomicInteger、AtomicIntegerArray等原子变量类,他们的实现原理大多是持有它们各自的对应的类型变量value,而且被volatile关键字修饰了。这样来保证每次一个线程要使用它都会拿到最新的值。

4、Lock锁(重点)

什么是Synchronized?[4]

Synchronized和lock

1.Lock是一个接口,而synchronized是关键字。2.synchronized会自动释放锁,而Lock必须手动释放锁。3.Lock可以让等待锁的线程响应中断,而synchronized不会,线程会一直等待下去。4.通过Lock可以知道线程有没有拿到锁,而synchronized不能。5.Lock能提高多个线程读操作的效率。6.synchronized能锁住类、方法和代码块,而Lock是块范围内的

synchronized是Java的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。JDK1.5以后引入了自旋锁、锁粗化、轻量级锁,偏向锁来有优化关键字的性能。

Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。


更多锁(ReentrantLock、ReadWriteLock读写锁)的文章请关注更多文章

5、集合类不安全

ArrayList、HashSet、HashMap线程都不安全

在集合中 Vector 和 HashTable 是线程安全的。源码中把各自核心方法添加上了synchronized 关键字。

Collections 工具类提供了相关的 API,可以让上面那 3 个不安全的集合变为安全的。

1.Collections.synchronizedCollection(c)2.Collections.synchronizedList(list)3.Collections.synchronizedMap(m)4.Collections.synchronizedSet(s)



References

[2] Java创建线程池的方式: https://cuizb.top/myblog/article/1646793688
[3] 线程池的理解以及使用: https://cuizb.top/myblog/article/1638890023
[4] 什么是Synchronized?: https://cuizb.top/myblog/article/1639581387


浏览 24
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报