多线程并发工具类

一、Fork-Join

什么是分而治之?

规模为N的问题,N<阈值,直接解决,N>阈值,将N分解为K个小规模子问题,子问题互相对立,与原问题形式相同,将子问题的解合并得到原问题的解。
在这里插入图片描述

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

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

public class FindDirsFiles extends RecursiveAction{

    private File path;//当前任务需要搜寻的目录

    public FindDirsFiles(File path) {
        this.path = path;
    }

    public static void main(String [] args){
        try {
            // 用一个 ForkJoinPool 实例调度总任务
            ForkJoinPool pool = new ForkJoinPool();
            FindDirsFiles task = new FindDirsFiles(new File("F:/"));
            pool.execute(task);//异步调用
            System.out.println("Task is Running......"); 
             task.join();//阻塞的方法
            System.out.println("Task end");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
  //业务方法
	@Override
	protected void compute() {
		
		List<FindDirsFiles> subTasks = new ArrayList<>();
		
		File[] files = path.listFiles();
		if(files!=null) {
			for(File file:files) {
				if(file.isDirectory()) {
					subTasks.add(new FindDirsFiles(file));
				}else {
					//遇到文件,检查
					if(file.getAbsolutePath().endsWith("txt")) {
						System.out.println("文件:"+file.getAbsolutePath());
					}
				}
			}
			if(!subTasks.isEmpty()) {
				for(FindDirsFiles subTask:invokeAll(subTasks)) {
					subTask.join();//等待子任务执行完成
				}
			}
		}
	}
}

//单线程递归读取某文件夹下的txt文件
  public static void readFile(File file) {
        File[] files = null;
        if (file != null) {
            files = file.listFiles();
        }
        if (files != null) {
            for (File f : files) {
                if (f.isDirectory()) {
                    readFile(f);
                } else {
                    if (f.getAbsolutePath().endsWith("txt"))
                        System.out.println(f.getAbsolutePath());
                }
            }
        }
    }

二、CountDownLatch

CountDownLatch是一个同步辅助类,它作用是让一个或多个线程等待其他的线程完成工作以后再执行,加强版Thread.join()。
CountDownLatch核心方法:

  • await 使调用该方法的线程处于等待状态,其一般是主线程调用。
  • countDown 用于使计数器减一,其一般是执行任务的线程调用
public class CountDownLatchDemo {

    private static final int NUM=5;
    //初始化
    static CountDownLatch countDownLatch=new CountDownLatch(NUM);

    public static void main(String[] args) throws Exception{
        System.out.println("开始执行");
        long start=System.currentTimeMillis();
        for(int i=0;i<NUM;i++){
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+":执行业务");
                countDownLatch.countDown();//线程执行完计数器减一
            }).start();

        }
        //主线程等所有线程完成工作才继续执行后面的代码,当计算器减到0阻塞结束
        countDownLatch.await(); 
        long end=System.currentTimeMillis();
        System.out.println("所有线程执行结束,耗时:"+(end-start)+"毫秒");
    }
}

三、CyclicBarrier
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。

public class CyclicBarrierDemo {
    private static final int NUM=5;
    private static CyclicBarrier cyclicBarrier=new CyclicBarrier(NUM);
	//所有线程开始才继续向下继续执行
    public static void main(String[] args) {
        for(int i=0;i<NUM;i++){
            new Thread(()->{
                System.out.println("开始");
                try {
                    cyclicBarrier.await();
                    System.out.println("开始执行");
                    Thread.sleep(10000);
                    System.out.println("执行完毕");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

CountDownLatch和CyclicBarrier区别

  • CountDownLatch放行由第三者控制,CyclicBarrier放行由一组线程本身控制
  • CountDownLatch放行条件>=线程数,CyclicBarrier放行条件=线程数
  • CountDownLatch是不可重置的,所以无法重用;而CyclicBarrier则没有这种限制,可以重用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值