在《Java多线程编程核心技术》有这样一道题,同时也是某公司(大华)的一道笔试题目。
假如有Thread1、Thread2、Thread3、Thread4四条线程分别统计C、D、E、F四个盘的大小,所有线程都统计完毕交给Thread5线程去做汇总,应当如何实现?
DiskMemory类如下
public class DiskMemory { // 记录磁盘的总大小 private int totalSize; // 获取一个磁盘的大小,采用随机数生成 public int getSize() { //加一是为了防止获取磁盘大小为0,不符合常理 return (new Random().nextInt(3) + 1) * 100; } //统计磁盘空间的大小 public synchronized void setSize(int size) { totalSize += size; } }根据给出的代码,补全剩余代码,实现该功能。
这主要考察的是线程的通信机制,多个线程共同协作完成任务
【第一种方法】
直接用join把线程5加入进去即可【第二种方法】
用juc包下提供的辅助工具类解决
用CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行
【分析关键字】
等待:线程5等待前四条线程完成任务后,才开始执行执行一次:每个线程任务只执行一次,共统计四次,四次结束后统计线程停止执行;累加线程开始执行CountDownLatch 是计数器,一个线程完成自己的线程任务,计数器就会减一(原子操作)。直到计数器减为0时,被阻塞的线程被唤醒执行。
countDown:原子类操作,计数器减一 await:调用该方法的线程被阻塞,直到计数器为0时被唤醒执行CountDownLatch类是一个同步倒数计数器,构造时传入int参数,该参数就是计数器的初始值,每调用一次countDown()方法,计数器减1,计数器大于0 时, await()方法会阻塞后面程序执行,直到计数器为0,后面被阻塞的方法才会得以实行。await(long timeout, TimeUnitunit),是等待一定时间,然后执行,不管计数器是否到0了。
在某些业务场景中,程序执行需要等待某个条件完成后才能继续执行后续的操作
【多任务下并行计算】:当某个处理的运算量很大时,可以将该运算任务拆分成多个子任务,等待所有的子任务都完成之后,父任务再拿到所有子任务的运算结果进行汇总
CyclicBarrier :同样是计数器,但是此计数器可被重置。CountDownLatch不可被重置。CyclicBarrier 更实用于多个线程之间的等待,直到所有线程满足条件后,才执行后续操作。类比王者荣耀或者CS等游戏,所有玩家进入到游戏房间后游戏才开始。
Semaphore :是信号量,它主要是用来限流。用来控制访问共享资源的线程数,控制同一时间并发线程的数目。比如说数据库连接池,资源数与线程数相同,一个线程只能获得一个连接,只能获取到一份连接,并且连接数有上限。
执行结果: