java并发包 J.U.C
JUC概述
J.U.C是指java.util.concurrent包下的并发类。
J.U.C包里的类有3部分:
线程安全相关的类
- Atomic类:AtomicLong等
- 锁对象:ReentrantLock,ReadWriteLock等
- 线程安全容器:ConcurrentHashMap,CopyOnWriteArrayList等
线程池框架: ExecutorService模式
为了提升房间清扫和人员使用的效率,主管提议使用动态人员的方式配置保洁(线程池)。 酒店每天至少有2名保洁值班(coreSize), 客人离店之后派遣2名保洁打扫。为了提升服务体验,如果有超过2个以上房客离店,主管将会从其他分部调派保洁。不幸的是总部规定每个酒店最多只能有10个保洁(maxSize)。如果没有可用的房间,新来要入店的房客只能等待(Queue)。
酒店资源有限,等待的队列不能无限的长(有界队列),否则有可能把酒店挤爆,哈哈哈,这种情况酒店就赚发了。在等待队列也满的时候, 需要合理策略(拒绝策略)处理。酒店前台可选的策略可以有:
1.拒绝接待新客人(DiscardPolicy),
2.不接待新客人通知总部(AbortPolicy,引发RejectExecutionException异常),
3.让客人自己打扫房间(CallerRunsPolicy),
4.队尾位置让给新来的客人(DiscardOldestPolicy)。这就是线程池的模型。
线程池模型核心关注:
- 3个容量大小(coreSize, maxSize, queueSize)和
- 4种拒绝策略(DiscardPolicy,AbortPolicy,CallerRunsPolicy,DiscardOldPolicy)。
总部会根据酒店客流量情况安排资源池配置参数(设置coreSize,maxSize和QueueSize),这即是如何设置线程池参数的问题。
- 在默认ThreadPoolExecutor.AbortPolicy ,处理程序会引发运行RejectedExecutionException后排斥反应。
- 在ThreadPoolExecutor.CallerRunsPolicy中,调用execute本身的线程运行任务。 这提供了一个简单的反馈控制机制,将降低新任务提交的速度。
- 在ThreadPoolExecutor.DiscardPolicy中 ,简单地删除无法执行的任务。
- 在ThreadPoolExecutor.DiscardOldestPolicy中, 会放弃执行时间最久的任务,转而接受新的任务。
Fork/Join框架
需要打扫的房间不多的时候, ExcutorSevice的模式运行效率很好。中午12点之后,大量空闲房间需要打扫。
如果还按照线程池的模式进行任务分配, 保洁人员刚打扫完4层的房间,保洁主管打电话过来说下一步打扫1楼的房间。保洁主管发现这种模式在需要打扫房间比较多的时间(任务比较多)时效率并不高。为了解决这个难题, 保洁主管想到了一个办法。
给每个保洁分配一层楼(一个线程一个工作队列),有楼层退房比较多, 有的比较少,为了解决公平和效率的问题。保洁完成本层任务后,随机去其他楼层帮忙(work stealing)。
保洁主管想到的这个方法就是Fork/Join模型。 Fork/Join类似ExecutorService,又有很多不同的地方。 Fork/Join可以把大任务(酒店),拆分成小任务(房间/楼层)。Fork/Join模型和ExecutorService模型最主要两点区别是:
- (1) 一个线程一个工作队列:每个人负责一个楼层。
- (2) 工作窃取:忙完自己的楼层,随机去其他楼层帮忙。
JUC框架图