ForkJoin并发框架实战,大数据处理同步

我粗略讲下关于ForkJoin的原理,ForkJoin框架是一个基于工作偷取算法的高并发框架。其主要的原理就是把要处理的数据,进行拆分,拆分之后再压入线程队列,然后下一级的线程队列再拆分,知道满足临界值的要求,然后对满足临界值的数据执行对应的操作。并且,ForkJoin框架里面有对应的ForkJoinPool管理线程,进行GC,然后其工作偷取算法会让空闲的线程A,去B线程的队列尾部偷取任务并执行。
关于java 1.8 新特性ForkJoin的源码剖析的详细介绍可以参考这篇文章
https://www.jianshu.com/p/f777abb7b251
下面我简要说下我的使用场景,关于同步区块链数据到mysql数据库。
贴一下主要的源码
这是设置ForkJoin要执行的任务
RecursiveTask Object 就是需要处理的数据对象。

public class ForkJoinWork extends RecursiveTask> {

    private Integer start;//起始值
    private Integer end;//结束值
    private List TxsAll;//操作的对象数组
    public static final  Integer critical = 100;//临界值
    TxsService txsService = (TxsService)AllBean.getBean("TxsService");
    public ForkJoinWork(Integer start, Integer end,List TxsAll) {
        this.start = start;
        this.end = end;
        this.TxsAll = TxsAll;
    }

    @Override
    protected List  compute() {
        //判断是否是拆分完毕
    	Integer lenth = end - start;
        if(lenth<=critical){
            //如果拆分完毕就插入数据库
        	List TxsPart= new ArrayList();
        	List AvailableList = new ArrayList();
        	GetBlockChainTxs.getTxsAvailable(start, end, TxsPart, AvailableList);
        	if(AvailableList.isEmpty()==false) {
        	txsService.insertTxsAvailableList(AvailableList);}
            return TxsPart;
        }else {
            //没有拆分完毕就开始拆分
        	Integer middle = (end + start)/2;//计算的两个值的中间值
        	List TxsPart1= new ArrayList();
        	List TxsPart2= new ArrayList();
        	List TxsPart3= new ArrayList();
            ForkJoinWork right = new ForkJoinWork(start, middle, TxsPart1);
            right.fork();//拆分,并压入线程队列
            ForkJoinWork left = new ForkJoinWork(middle+1,end , TxsPart2);
            left.fork();//拆分,并压入线程队列

            TxsPart3.addAll(right.join());
            TxsPart3.addAll(left.join());
            //合并
            return TxsPart3;
        }
    }
}

调用执行任务的代码

public class ForkJionTest extends Thread{
	   TxsService txsService = (TxsService)AllBean.getBean("TxsService");
       private int start;
       private int end;
       private int SqlHeight;
       boolean b = false;//是否追上
   	public void setHeight(int start,int end) {
		this.start = start;
		this.end =end;
	}
	
	@Override
    public void run() {
	    ForkJoinPool forkJoinPool = new ForkJoinPool();//实现ForkJoin 就必须有ForkJoinPool的支持
	    int chainHeight=GetBlockChainTxs.getTxsMaxHeight();
	    int updataHeight=10000;
	System.out.println(chainHeight);

	 if(txsService.findMaxHeight()==null) {
	    SqlHeight=1;
	    while(!b) {
	    	try {
	    		setHeight(SqlHeight,updataHeight);
	    		  List TxsAll=null;
		          ForkJoinTask> task = new ForkJoinWork(start,end,TxsAll);//参数为起始值与结束值
		          TxsAll = forkJoinPool.invoke(task);
		          txsService.insertTxsList(TxsAll);
	    	}catch (Exception e) {
				// TODO: handle exception
	    		System.out.println(e.toString());
			}finally {
				SqlHeight =txsService.findMaxHeight()+1;
				updataHeight+=10000;
				System.out.println(SqlHeight);
				if(chainHeight<=SqlHeight) {
					b=true;
				}
			}
	    }
	 }
	 if(txsService.findMaxHeight()!=null) {
		    SqlHeight=txsService.findMaxHeight()+1;
		    while(!b) {
		    	try {
		    		setHeight(SqlHeight,updataHeight);
		    		  List TxsAll=null;
			          ForkJoinTask> task = new ForkJoinWork(start,end,TxsAll);//参数为起始值与结束值
			          TxsAll = forkJoinPool.invoke(task);
			          txsService.insertTxsList(TxsAll);
		    	}catch (Exception e) {
					// TODO: handle exception
		    		System.out.println(e.toString());
				}finally {
					SqlHeight =txsService.findMaxHeight()+1;
					updataHeight+=10000;
					System.out.println(SqlHeight);
					if(chainHeight<=SqlHeight) {
						b=true;
					}
				}
		    }
		    while(b) {
		    	try {
		    		System.out.println("---------------------一秒更新一次了---------------------------");
		    		setHeight(SqlHeight,updataHeight);
		    		  List TxsAll=null;
			          ForkJoinTask> task = new ForkJoinWork(start,end,TxsAll);//参数为起始值与结束值
			          TxsAll = forkJoinPool.invoke(task);
			          txsService.insertTxsList(TxsAll);
			          Thread.sleep(800);
		    	}catch (Exception e) {
					// TODO: handle exception
		    		System.out.println(e.toString());
				}finally {
					SqlHeight =txsService.findMaxHeight()+1;
					updataHeight+=10000;
					System.out.println(SqlHeight);
				}
		    }
		 }


	    
	}
}

关于调用这边主要的实现方法是:

 ForkJoinPool forkJoinPool = new ForkJoinPool();//实现ForkJoin 就必须有ForkJoinPool的支持
 	    int chainHeight=GetBlockChainTxs.getTxsMaxHeight();
	    int updataHeight=10000;//这里调整要查询的区块高度
 setHeight(SqlHeight,updataHeight);
	    		  List TxsAll=null;
		          ForkJoinTask> task = new ForkJoinWork(start,end,TxsAll);//参数为起始值与结束值
		          TxsAll = forkJoinPool.invoke(task);//将任务压入线程池
		          txsService.insertTxsList(TxsAll);//这里储存处理过1万条的区块链数据

我的实现原理主要是,将区块链上所有的高度信息List,有交易数据的区块信息List用这两个List对象数据进行存储,再分别将这两个数据存到不同的数据表里去。
执行的效率为6秒1万条数据的同步。是普通线程处理数据效率的10倍左右。

关于List在并发情况下的线程安全问题,众所周知的是,线程安全的数组只有Vector ,HashTable,StringBuffer这三个。
但ForkJoin框架避开了这一点,利用不停拆分的原理,保证了数组在处理时,不会出现重复或者不一致的情况。

你可能感兴趣的:(并发技术)