并发基础_13_并发_框架_Fork/Join

Fork/Join框架


Fork/Join框架是Jdk1.7提供的一个用于并发执行任务的框架。

它将一个大任务分割为若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。


Fork就是将一个大任务切分为若干个子任务并行的执行;

Join就是合并这些子任务的执行结果,最后得到这个大任务的结果。

(如果你了解过Hadoop的MapReduce的话,会发现,和这个玩意很像耶...)



Fork/Join 实例Demo

public class Task extends RecursiveTask<Integer> {

	private static final long serialVersionUID = 1L;

	private List<Integer> numberList;
	private int start;
	private int end;
	private int THRESHOID = 10;

	public Task(List<Integer> numberList) {
			this.numberList = numberList;
			start = 0;
			end = this.numberList.size() - 1;
	}

	public Task(List<Integer> numberList, int start, int end) {
			this.numberList = numberList;
			this.start = start;
			this.end = end;
	}

	@Override
	protected Integer compute() {

	if (end - start <= THRESHOID) {
			return sum();
	} else {
			int pivot = (end + start) / 2;

	Task task1 = new Task(numberList, start, pivot);
	Task task2 = new Task(numberList, pivot + 1, end);
	task1.fork();
	task2.fork();
	return task1.join() + task2.join();
	}

	}

	private Integer sum() {
			Integer sum = 0;
			for (int i = start; i <= end; i++) {
					sum += this.numberList.get(i);
			}
			return sum;
	}

}

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;

public class Main {

	public static void main(String[] args) throws Exception {
			ForkJoinPool pool = new ForkJoinPool();

	Task task = new Task(getData(100));

	Future<Integer> result = pool.submit(task);
	System.out.println(result.get());

	}

	private static List<Integer> getData(int len) {
			List<Integer> list = new ArrayList<Integer>();
			for (int i = 1; i <= len; i++) {
					list.add(i);
			}
			return list;
	}

}

输出结果:
	5050



Demo2
public class CountTask extends RecursiveTask<Integer> {

	private static final long serialVersionUID = 1L;

	private static final int THRESHOLD = 2;// 阀值
	private int start;
	private int end;

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

	@Override
	protected Integer compute() {

	int sum = 0;

	boolean canCompute = (end - start) <= THRESHOLD;

	if (canCompute) {// 如果任务足够小就计算任务

	for (int i = start; i <= end; i++) {
			sum += i;
	}

	} else {// 如果任务大于阀值,就分裂成两个子任务计算
			int middle = (start + end) / 2;

	CountTask leftTask = new CountTask(start, middle);
	CountTask rightTask = new CountTask(middle + 1, end);

	// 执行子任务
	leftTask.fork();
	rightTask.fork();

	// 等待子任务执行完成,并得到其结果
	int leftResult = leftTask.join();
	int rightRestul = rightTask.join();

	// 合并子任务结果
	sum = leftResult + rightRestul;

	}

	return sum;
	}

}

public class TestMain {

	public static void main(String[] args) throws Exception {

	ForkJoinPool pool = new ForkJoinPool();

	CountTask countTask = new CountTask(1, 9);
	Future<Integer> result = pool.submit(countTask);

	System.out.println(result.get());
	}

}

输出结果:
	45



工作窃取算法

工作窃取算法是指:

某个线程从其他队列中窃取任务来执行。


举个栗子:

假设我们有一个比较大得到任务,把这个任务分割为若干不依赖的子任务,为了减少线程间的竞争,把这些子任务分别放到不同的任务队列中,并为每个队列创建一个单独的线程来执行队列里的任务,线程队列一一对应。


有的线程会先把自己队列里的任务干完,而其他线程对应的队列中还有任务等待处理。

干完活的线程与其等着,不如去帮其他线程干活,于是它就去其他线程的任务队列中窃取一个任务线程来执行。


为了减少窃取任务时,线程之间的竞争,通常采用双端队列,被窃取任务线程永远从队列的头部拿任务执行,窃取任务线程永远从双端队列的尾部拿任务执行。


工作窃取算法的优点:充分利用线程进行并行计算,减少了线程间的竞争。

工作窃取算法的缺点:在某些情况下还是存在竞争的,比如双端队列中只有一个任务时。

并且该算法会消耗更多的系统资源,比如创建多个线程和多个双端队列。


Fork/Join框架的设计

1. 分割任务

首先我们需要有一个fork类来把大任务分割成子任务,有可能子任务还是很大,所以需要不停的分割,

直到分割出的子任务足够小。


2. 执行任务并合并结果

分割的子任务分别放在双端队列中,然后启动几个线程分别从双端队列中获取任务执行。

子任务执行完的结果都同一放在一个队列中,启动一个线程从这些队列中拿结果数据,然后合并这些数据。


Fork/Join使用两个类来完成以上两件事。

a. ForkJoinTask:

1) 使用ForkJoin框架,首先必须创建一个ForkJoin任务。它提供任务中执行fork()和join()操作的机制。

2) 通常情况下,不需要直接继承ForkJoinTask类,只需要继承它的两个子类:

RecursiveAction:用于没有返回结果的任务

RecutsiveTask:用于有返回结果的任务


b. ForkJoinPool:

ForkJoinTask需要通过ForkJoinPool来执行。


Fork/Join框架暂时先说这么多

有空的话后续在《JAVA并发编程核心方法与框架》系列笔记中详述


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值