java高并发实战编程(三)

一:Fork/Join 框架:

     分而治之的思想:也就是将一项任务分为多个执行过程进行,最后将结果进行整合。在Linux通过fork()函数创建子进程,使得系统进程可以多一个执行分支(线程),要等待这个执行分支执行完毕,才有可能得到最终结果,而join()就表示等待。

    由于线程池的优化,提交的任务和线程的数量并不是一对一的关系。大多数情况下,一个物理线程需要处理多个任务,因此,每个线程必然需要拥有一个任务队列。因此,很有可能线程A执行完所有任务后,线程B还有一堆任务等待处理,此时,线程A就会帮助B,从B的任务队列中拿一个任务过来处理,尽可能达到平衡。当线程帮助别人时,总是从任务队列的底部开始拿数据,而线程试图执行自己的任务时,则是从顶部开始拿,有利于避免数据竞争。

    如果毫无顾忌的使用fork()开启线程进行处理,可能导致开启过多线程而严重影响性能。因此在JDK中,给出了一个ForkJoinPool线程池,对于fork()并不急着开启线程,而是提交给ForkJoinPool线程池进行处理,以节省系统资源。

1.2 ForkJoinPool的一个重要接口:

   public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task)

    你可以向ForkJoinPool线程池提交一个ForkJoinTask任务。所谓ForkJoinTask任务就是支持fork()分解以及join()等待的任务。ForkJoinTask有两个重要的子类,RecursiveAction和RecursiveTask.分别表示没有返回值的任务和可以携带返回值的任务

      代码:

/**
 * forkJoin框架案例
 */
public class ThreadUtils extends RecursiveTask<Long> {
    private static final int THRESHOLD = 10000;
    private long start;
    private long end;

    public ThreadUtils(long start,long end){
        this.start = start;
        this.end = end;
    }


    protected Long compute() {
        long sum = 0;
        boolean canCompute = (end -start)<THRESHOLD;
        if (canCompute){
            for (long i=start;i<=end;i++){
                sum+=i;
            }
        }else {
            //分成100个小任务
            long step = (start+end)/1000;
            ArrayList<ThreadUtils> subTasks = new ArrayList<>();
            long pos = start;
            for (int i=0;i<100;i++){
                long lastOne = pos+step;
                if (lastOne>end) lastOne=end;
                ThreadUtils subTask = new ThreadUtils(pos,lastOne);
                pos+=step+1;
                subTasks.add(subTask);
                subTask.fork();
            }
            for (ThreadUtils t : subTasks){
                sum+=t.join();
            }
        }
        return sum;
    }


    public static void main(String[] args){
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ThreadUtils task = new ThreadUtils(0,200000L);
        ForkJoinTask<Long> result = forkJoinPool.submit(task);
        try {
            long res = result.get();
            System.out.println("sum="+res);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

  注意:分的任务大小不同,结果好像也不一样????

二:JDK并发容器:

   构造线程安全的Map:使用代理模式,从原map中获取数据,其本身只是作为一个加锁的工具

public static Map map = Collections.synchronizedMap(new HashMap());

  上述案例 返回  SynchronizedMap,而其实现方法就是使用mutex锁进行 synchronized锁定。方法都要获取锁操作,性能不高。

猜你喜欢

转载自blog.csdn.net/qq_35152911/article/details/85720637