JDK7自带的分布式处理方式Fork/Join框架

什么是Fork/Join框架?

fork/join框架是ExecutorService接口的一个实现,可以充分利用多核处理器的优势,编写出并行执行的程序,提高应用程序的性能;主要是为了处理那些可以被递归拆分的任务。
fork/join框架与其它ExecutorService的实现类相似,会给线程池中的线程分发任务,实现异步多线程处理任务,进而大大提高处理效率,不同之处在于它使用了工作窃取算法,所谓工作窃取,指的是对那些处理完自身队列中任务的线程,会从其它的任务队列中窃取任务执行;比如大批量任务使用Fork/Join处理,并且被拆分成A,B两部分进行处理,A,B各自先处理自己WorkQueue中的ForkJoinTask,假如A率先处理完自己的WorkQueue中的ForkJoinTask,那么A会从B WorkQueue中的尾部拿走一些ForkJoinTask来处理,进而提高效率。
fork/join框架提交处理任务使用的是自带的ForkJoinPool线程池

应用场景1:计算1+…+100000

package forkJoin;


import java.util.concurrent.RecursiveTask;


public class MyForkJoinTest extends RecursiveTask<Long> {

    /**
	 * 
	 */
	private static final long serialVersionUID = -5363777012182729166L;

	// 最大容量
    private static final Long MAX_CAPACITY = 10000L;

    private Integer start;

    private Integer end;

    public MyForkJoinTest(Integer start, Integer end) {
        this.start = start;
        this.end = end;
    }

    protected Long compute() {
        Long result = 0L;
        if(end-start<MAX_CAPACITY){
            for (int i = 1 ; i <= end-start ; i++ ){
                result+=i;
            }
        }else{// 超过最大容量则进行分拆任务
            // 计算容量中间值
            int middle = (start + end)/2;
            // 进行递归
            MyForkJoinTest forkJoinTest1 = new MyForkJoinTest(start, middle);
            MyForkJoinTest forkJoinTest2 = new MyForkJoinTest(middle + 1, end);
            // 执行任务
            forkJoinTest1.fork();
            forkJoinTest2.fork();
            // 等待任务执行并返回结果(阻塞)
            result = forkJoinTest1.join() + forkJoinTest2.join();
        }
        return result;
    }
}

package test;

import java.util.concurrent.ForkJoinPool;

import forkJoin.MyForkJoinTest;
import org.junit.Test;

public class ForkJoin {
	
	/**
	 * 第一种执行方式:可以直接将任务提交给ForkJoinPool。
	 * ForkJoinPool.execute(ForkJoinTask task);该方法没有返回值
	 * ForkJoinPool.invoke(ForkJoinTask task);直接有返回值。
	 */
	@Test
	public void testForkJoin1(){
		ForkJoinPool pool = new ForkJoinPool();
		MyForkJoinTest test = new MyForkJoinTest(1,100000);
		Long result = pool.invoke(test);
		System.out.println(result);
	}
	
	/**
	 * 第二种执行方式:RecursiveTask.fork()开始执行。
	 * 			   RecursiveTask.join()返回执行结果。
	 */
	@Test
	public void testForkJoin2(){
		MyForkJoinTest test = new MyForkJoinTest(1,100000);
		Long result = test.fork().join();
		System.out.println(result);
	}
}

应用2:异步执行相关代码逻辑;

例子:开发中,有获取搜索列表的接口。一般需要获取二部分数据,搜索到的结果集和已经满足搜索条件的count值;需要异步执行提高效率时,会额外开一个新线程new Runnable(()-{}),这样可能会过多的消耗系统资源。所以我们会同时使用线程池。可能是自定义的线程池,也可能是使用自带的例如:newFixedThreadPool 。我们也可以使用fork/Join实现。

// async invoke
    RecursiveTask<List<DTO>> searchTask = (RecursiveTask<List<DTO>>) new RecursiveTask<List<DTO>>() {
        @Override
        protected List<DTO> compute() {
            return service.search(param);
        }
    }.fork();
    RecursiveTask<Integer> countTask = (RecursiveTask<Integer>) new RecursiveTask<Integer>() {
        @Override
        protected Integer compute() {
            return service.count(param);
        }
    }.fork();
    
    // 搜索结果集
    List<DTO> result =  searchTask.join();
    // count值
    Integer count = countTask.join();

注意:Fork/Join最大的优势是充分CPU多核计算效率,但也会使得CPU在处理的时,把整个CPU占满,所以,Fork/Join只适合一些离线系统,不适合在线系统应用中使用Fork/Join,如果使用的话,在Fork/Join处理时间内,系统的其他功能全部阻塞挂掉,这点要特别注意。。测试代码如下:我拆分30000个子任务,我的CPU占用达到了98%,对于在线系统这是很危险的。选择使用时该框架时要好好考虑下哦。如果仅仅是像应用2只是为了异步执行某些逻辑的场景下使用F/J是没问题的。。

package forkJoin;


import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;


public class MyForkJoinTest extends RecursiveTask<Long> {

    /**
	 * 
	 */
	private static final long serialVersionUID = -5363777012182729166L;

	// 最大容量
    private static final Long MAX_CAPACITY = 10L;

    private Integer start;

    private Integer end;

    public MyForkJoinTest(Integer start, Integer end) {
        this.start = start;
        this.end = end;
    }

    protected Long compute() {
        Long result = 0L;
        if(end-start<MAX_CAPACITY){
            for (int i = 1 ; i <= end-start ; i++ ){
            	  System.out.println(Thread.currentThread().getName()+"的i值:"+i);
            	  result+=i;
            }
        }else{// 超过最大容量则进行分拆任务
            // 计算容量中间值
            int middle = (start + end)/2;
            // 进行递归
            MyForkJoinTest forkJoinTest1 = new MyForkJoinTest(start, middle);
            MyForkJoinTest forkJoinTest2 = new MyForkJoinTest(middle + 1, end);
            // 执行任务
            forkJoinTest1.fork();
            forkJoinTest2.fork();
            // 等待任务执行并返回结果(阻塞)
            result = forkJoinTest1.join() + forkJoinTest2.join();
        }
        return result;
    }
    
    public static void main(String [] args) throws Exception{
    	System.out.println(Runtime.getRuntime().availableProcessors());
    	ForkJoinPool fjp = new ForkJoinPool();
    	MyForkJoinTest myForkJoinTest = new MyForkJoinTest(0,300000);
    	fjp.invoke(myForkJoinTest);
    }
}
	

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值