1.工作窃取算法
每个线程有一个工作队列,线程1有一个工作队列1,线程2有一个工作队列2,当线程1将队列1中的任务执行完了以后就窃取队列2中的任务去执行。
执行任务的队列从头到尾执行,窃取线程从尾部向头部执行任务。
优点:充分了用线程的执行时间,且减少了资源抢占的情况。(每个线程的资源独立)
缺点:会创建多个线程队列。而且当多个线程执行到最后只有一个任务的时候可能存在抢占资源的情况。
2.代码
fork/jion机制局限性:
1.只能通过fork开启线程,jion同步线程,不可以使用其他线程同步的手段。如果使用任务执行了sleep,那么执行该任务的线程都无法执行其他操作了。
2.不可以IO操作。
ForkJoinPool管理资源状态,RecursiveTask进行fork和join。
@Slf4j
public class ForkJoinExample1 extends RecursiveTask<Integer> {
private static final int threshold = 2;
private int start=1;
private int stop =100;
public ForkJoinExample1(int start,int stop){
this.start = start;
this.stop = stop;
}
// 执行1加到100
@Override
protected Integer compute() {
int sum = 0;
boolean canCompute = (stop-start)<=threshold;
if (canCompute){ // 为了防止两个线程抢占队列里仅有的一个数,当两个线程运行到距离很近的时候就直接fori求和
for (int i = start; i <= stop; i++) {
sum+=i;
}
}else {
//如果两个数差距很远就分裂成两个任务
int middle = (start+stop)/2;
ForkJoinExample1 leftTask = new ForkJoinExample1(start,middle);
ForkJoinExample1 rightTask = new ForkJoinExample1(middle+1,stop);
//执行子任务
leftTask.fork();
rightTask.fork();
//jion等待执行结束
int leftResult = leftTask.join();
int rightResult = rightTask.join();
//合并任务
sum = leftResult+rightResult;
}
return sum;
}
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool();
ForkJoinExample1 task = new ForkJoinExample1(1,100);
Future<Integer> future = pool.submit(task);
try {
log.info("result - {}",future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
运行结果: