Fok/join Pool

引用 ifeve

work-stealing算法

工作窃取(work-stealing)算法是指某个线程从其他队列里窃取任务来执行。
那么为什么需要使用工作窃取算法呢?
假如我们需要做一个比较大的任务,我们可以把这个任务分割为若干互不依赖的子任务,为了减少线程间的竞争,于是把这些子任务分别放到不同的队列里,并为每个队列创建一个单独的线程来执行队列里的任务,线程和队列一一对应,比如A线程负责处理A队列里的任务。
但是有的线程会先把自己队列里的任务干完,而其他线程对应的队列里还有任务等待处理。干完活的线程与其等着,不如去帮其他线程干活,于是它就去其他线程的队列里窃取一个任务来执行。而在这时它们会访问同一个队列,所以为了减少窃取任务线程和被窃取任务线程之间的竞争,通常会使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行。

在这里插入图片描述
工作窃取算法的优点是充分利用线程进行并行计算,并减少了线程间的竞争

当其它线程只存在一个任务时,工作窃取算法可能会存在竞争.

ForkJoinPool

JDK 1.7 时,标准类库添加了 ForkJoinPool,作为对 Fork/Join 型线程池的实现。Fork 在英文中有 分叉 的意思,而Join 有 合并 的意思。
ForkJoinPool的功能也是如此:Fork 将大任务分叉为多个小任务,然后让小任务执行,Join 是获得小任务的结果,然后进行合并,将合并的结果作为大任务的结果 —— 并且这会是一个递归的过程 —— 因为任务如果足够大,可以将任务多级分叉直到任务足够小。
在这里插入图片描述

使用Fork/Join框架,必须要了解两个类:

  • ForkJoinTask: 我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。它提供在任务中执行fork()和join()操作的机制,通常情况下我们不需要直接继承ForkJoinTask类,而只需要继承它的子类,Fork/Join框架提供了以下两个子类:
    • RecursiveAction:用于没有返回结果的任务。
    • RecursiveTask: 用于有返回结果的任务。
public abstract class RecursiveAction extends ForkJoinTask<Void> {
}

public abstract class RecursiveTask<V> extends ForkJoinTask<V> {
}
  • ForkJoinPool :ForkJoinTask需要通过ForkJoinPool来执行,任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。当一个工作线程的队列里暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任务。

**ForkJoinPool-API **

    /**
     * 执行一个带返回值的任务 --该方法是阻塞的,直到任务执行完毕,该方法才会停止阻塞并返回任务的执行结果。
     * @param  task  通常为 RecursiveTask类型
     * @return    返回执行结果
     */
    public <T> T invoke(ForkJoinTask<T> task) {}

    /**
     * 不带返回值的任务 --- 非阻塞的
     */
    public void execute(ForkJoinTask<?> task) {}

    /**
     * 方法是---非阻塞的,调用之后将任务提交给 ForkJoinPool 去执行便立即返回
     * 
     *  ForkJoinTask实现了Future接口,通过 future.get()获取结果
     */
    public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) {}

demo

需求
计算 1+2+…+ 100 的结果。
如果我们希望每个子任务最多执行十个数的相加,那么我们设置分割的阈值是 10

code

public class M1_创建ForkJoin池 {
	/**
	 * 需求是:计算 1+2+....+ 100 的结果。
	 * 如果我们希望每个子任务最多执行十个数的相加,那么我们设置分割的阈值是 10
	 *
	 * RecursiveAction:用于没有返回结果的任务。
	 * RecursiveTask :用于有返回结果的任务。
	 */

	static class MyCountRecursiveTask extends RecursiveTask<Integer> {
		private static final int THRESHOLD = 10;
		private int start ;
		private int end;

		public MyCountRecursiveTask(int start, int end) {
			this.start = start;
			this.end = end;
		}

		@Override
		protected Integer compute() {
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			Integer sum = 0;
			boolean canCal = (end - start) <= THRESHOLD;
			if(canCal){
				for (int i = start; i <= end ; i++) {
					sum += i;
				}
			}else{
				int middle = (start + end) / 2;
				MyCountRecursiveTask leftTask = new MyCountRecursiveTask(start, middle);
				MyCountRecursiveTask rightTask = new MyCountRecursiveTask(middle+1, end);
				leftTask.fork(); //执行子任务left
				rightTask.fork();//执行子任务right

				int leftResult = leftTask.join();
				int rightResult = rightTask.join();

				sum = leftResult + rightResult;
			}
			return sum;
		}
	}

	public static void main(String[] args) throws ExecutionException, InterruptedException {
		MyCountRecursiveTask task = new MyCountRecursiveTask(1, 10000);

		ForkJoinPool pool = new ForkJoinPool();
		Future future = pool.submit(task);

	do {
			System.out.println("********************************************************");
			System.out.printf("Main: Pool Size: %d\n",pool.getPoolSize());
			System.out.printf("Main: Active Thread Count: %d\n",pool.getActiveThreadCount());
			System.out.printf("Main: Thread Steal: %d\n",pool.getStealCount());
			System.out.printf("Main: Parallelism: %d\n",pool.getParallelism());
			try {
				TimeUnit.MILLISECONDS.sleep(5);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} while (!task.isDone());

		System.out.println(future.get());

		//如果出现异常,则显示异常信息
		if(task.isCompletedAbnormally()){
			System.out.println(task.getException());
		}

	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值