thread_fork/join并发框架1
一.线程并发控制  Thread、Executor、ForkJoin和Actor
  1.裸线程
      Runnable接口,调用.start()开始,没有现成的API来结束线程,你需要自己来实现,通过类似boolean类型的标记来通讯
使用Runnable对象,然后创建对应的Thread对象来控制程序中这些线程的创建、执行以及线程的状态
2.ExecutorFramework(Executor和ExecutorService接口):执行器框架将任务的创建和执行进行了分离,通过这个框架只需要实现Runnable接口的对象和使用Executor对象,然后将Runnable对象发送给执行器,执行器再负责这些任务锁需要的线程,包括线程的创建管理已经线程的结束
  public interface Executor {	 
		    void execute(Runnable command);	 
	  }
    ExecutorService管理executor的生命周期,以及CompletionService会抽象掉更多细节,作为已完成任务的队列
    Executors.newFixedThreadPool(4) 
   3.通过并行流,使用ForkJoinPool (FJP)
Fork/Join 分解/合并框架
用来解决分治技术,将问题拆分成若干小任务,在一个任务中,先检查要解决任务的问题的大小,决定是否再拆分任务。如果不需要拆分任务了,就在当前任务中解决问题。然后根据需要返回任务的结果。
ForkJoinPool类看作一个特殊的Executor执行器类型,这个框架包括以下两个操作: 
 分解(Fork)操作:当需要将一个任务拆分成更小的多个任务时,在框架中执行这些任务 
 合并(Join)操作: 当一个主任务等待其创建的多个子任务的完成执行。
 Fork/Join 和 ExecutorFramework 主要的区别在于 工作窃取算法(Work-StealingAlgroithms),使用Join操作让一个主任务等待它所创建的子任务的完成,执行这个任务的线程称之为 工作者线程(worker Thread),工作者线程会寻找其他任未被执行的任务,然后开始执行。 什么是工作窃取算法?:就是指某个线程从其他队列里窃取任务来执行。从而提升了性能。
为了达到以上的效果,Fork/Join框架有以下几点限制:
a. 任务只能使用fork() 和 join() 操作当同步机制。如果使用其他的同步机制,工作线程就不能执行其他的任务,当然这些任务是在同步操作里时。比如在Fork/Join框架中将一个任务休眠,正在执行这个任务的工作者线程在休眠期内不能执行另一个任务。
b. 任务不能执行I/O操作,比如文件数据的读取与写入
c. 任务不能抛出非运行时异常(Checke Exception),必须在代码中处理这些异常
4.actor模型中  Akka Actors
      actor模型中,一切都看做是一个actor。一个actor是一个计算实体,它可以从其他actor那里接收消息。在应答消息时,它可以给其他actor发送消息,或者创建新的actor并与之交互,或者只改变自己的内部状态。
      这是一个非常强大的概念。生命周期和消息传递由你的框架来管理,你只需要指定计算单元是什么就可以了。另外,actor模型强调避免全局状态,这会带来很多便利。你可以应用监督策略,例如免费重试,更简单的分布式系统设计,错误容忍度等等。
二.简单应用举例
转自 http://blog.csdn.net/mr_zhuqiang/article/details/48300229
Fork/Join框架的核心是由ForkJoinPool和ForkJoinTask组成
  ForkJoinPool : 这个类实现了 ExecutorServic接口和工作窃取算法。它管理工作者线程,并提供任务的状态信息,以及任务的执行信息
  ForkJoinTask :是一个将在ForkJoinPool中执行的任务的基类
  Fork/Join框架提供了在一个任务里执行fork和join操作的机制和控制任务状态的方法,通常,为了实现Fork/Join任务,需要实现以下两个类之一的子类。
RecursiveAction :用于任务没有返回结果的场景,一个ForkJoinTask任务类,递归无结果的任务类。类似callable一样的线程任务,
RecursiveTask : 用于任务有返回结果的场景
下示例描述了,批量修改很多商品的价格,使用Fork/Join线程池 和 RecursiveAction(ForkJoinTask)来实现 递归的分配任务执行
    public static void main(String[] args) throws InterruptedException {
        // 生成商品数据
        List<Product> list = new ArrayList<Product>();
        for (int i = 0; i < 40; i++) {
            Product p = new Product("苹果" + i, 10);
            list.add(p);
        }
        ///////////////////////////////////////////////
        ForkJoinPool fjp = new ForkJoinPool();
        Task task = new Task(list, 0, list.size(), 19);
        fjp.execute(task);
        // fjp.shutdown(); //关闭线程池
        // fjp.awaitTermination(1, TimeUnit.MINUTES);
        //等待超时。结合shutdown来让任务一完成就继续执行下面的代码
        // 使用循环的方式来查看任务的信息
        do {
            System.out.printf("活跃线程:%s,这一个参数  %s,并行执行的最大数量:%s\n",
                    fjp.getActiveThreadCount(),
                    fjp.getStealCount(),
                    fjp.getParallelism());
        } while (!task.isDone()); // 如果任务还未完成,则继续获取信息
        // 如果这个任务完成没有抛出异常并没有取消。
        if (task.isCompletedNormally()) {
            System.out.println("main:任务完成");
        }
        System.out.println("main:------------------------------  打印任务结果");
        for (Product product : list) {
            int price = product.getPrice();
            String name = product.getName();
            if (price != 19) { // 结果不是所期望的。就打印出来
                System.out.println(name + "," + price);
            }
        }
        System.out.println("main:------------------------------  打印任务结束");
    }
}
class Product {
    private String name;
    private int price;
    public Product(String name, int price) {
        this.name = name;
        this.price = price;
    }
    public String getName() {
        return name;
    }
    ......
}
class Task extends RecursiveAction {
    private List<Product> list; // 所有任务
    private int start;          // 处理任务的开始索引
    private int end;            // 处理任务的结束索引
    private int price;          // 更改的价格
    public Task(List<Product> list, int start, int end, int price) {
        this.list = list;
        this.start = start;
        this.end = end;
        this.price = price;
    }
    @Override
    protected void compute() {
        if (end - start <= 10) { // 每个task 只能处理10条数据。
            System.out.printf("起始:start:%s,end:%s\n", start, end);
            update();
        } else { // 多余的数据,则需要分给更多的任务
            int middle = (end + start) / 2; // 因为是索引。所以需要开始和结尾相加,然后除以2 就能得到
                                            // 两个索引之间的数值
            Task task1 = new Task(list, start, middle, 19);
            Task task2 = new Task(list, middle, end, 19);
            System.out.printf("分析:middle:%s,start:%s,end:%s\n", middle, start, end); // 方便推算
            // 这里把任务分成了2半递归执行。
            invokeAll(task1, task2);
        }
    }
    // 根据给定的起始索引和结束索引更新结果
    private void update() {
        for (int i = start; i < end; i++) {
            Product product = list.get(i);
            product.setPrice(price);
            System.out.printf("%s,修改了价格,索引:%s,%s,%s\n",
             Thread.currentThread().getName(),
              i,product.getName(),product.getPrice() );
        }
    }
}
结果分析:
   起始信息:我们有40个商品,每个任务处理10个商品。刚好4个工作线程处理。
  分析信息:去中间索引,这个分析在商品数量不能被2整除的时候很有用,在不能被2整除的情况下,该示例任然会尽可能的均衡分配任务的数量
工作原理
  invokeAll方法来执行一个主任务锁创建的多个子任务,这个是一个同步的调用,主任务将等待子任务的完成,然后继续执行(有可能是结束),当这个主任务等待它的子任务时,执行这个主任务的工作者线程接收另一个等待执行的任务并开始执行(并行),正因为有了这个行为,所以说Fork/Join框架提供了一种比Runnable和Callable对象更加高效的任务管理机制。
    ForkJoinTask类的invokeAll方法是执行器框架ExecutorFramework和Fork/Join框架之间的主要差异之一。在执行器框架中。 
    在执行器框架中:所有的任务必须发送给执行器 
    在Fork/Join框架:线程池中包含了待执行方法的任务,任务的控制也是在线程池中进行的,我们在task类中使用了invokeAll方法,task类继承了RecursiveAction,而RecursiveAction类则继承了ForkJoinTask.
三.常用方法
1.fork join get
fork()方法允许ForkJoinTask任务异步执行,也允许一个新的ForkJoinTask从存在的ForkJoinTask中被启动。
   join()方法允许一个ForkJoinTask等待另一个ForkJoinTask执行完成。
fork()只会让ForkJoinPool调度一个新的任务,而不会创建子虚拟机。
RecursiveTask.join() : 也是用来获取任务的合并结果
RecursiveTask.get(long timeout,TimeUnit unit) : 该方法,是给定一个指定的超时时间,如果超时还没有返回结果则返回null
invokeAll(task1,task2): 是一个同步的方法,任务会被挂起,等待子任务发送到线程池中并且直到完成
2.RecursiveAction 和RecursiveTask
RecursiveAction的实例代表执行没有返回结果。
   RecursiveTask会有返回值。下面例子 返回值
public class ForkJoin2Test {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //生成随机矩阵
        final int rows = 10000; // 矩阵行数
        final int cols = 10000; // 矩阵列数
        final int number = 5;   // 查找的数字
        long start = System.currentTimeMillis();
        MatrixMock mock = new MatrixMock(rows, cols, number); // 生成矩阵对象
        long end = System.currentTimeMillis();
        System.out.println("创建矩阵花费时间:" + (end - start));
        //执行任务
        ForkJoinPool pool = new ForkJoinPool();
        Task2 task = new Task2(mock, 0, rows, 5);
        start = System.currentTimeMillis();
        pool.execute(task);
        pool.shutdown();
        //
        pool.awaitTermination(1, TimeUnit.MILLISECONDS);
        System.out.println("线程搜索的结果是:" + task.get());
        end = System.currentTimeMillis();
        System.out.println("线程搜索时间是:" + (end - start));
        start = System.currentTimeMillis();
        int temp = 0;
        for (int i = 0; i < rows; i++) {
            int[] rs = mock.getRow(i);
            for (int row : rs) {
                if (5 == row) {
                    temp++;
                }
            }
        }
        end = System.currentTimeMillis();
        System.out.println("单线程搜索结果是:" + temp);
        System.out.println("单线程搜索时间是:" + (end - start));
    }
}
// 任务类。查找数字出现的次数
class Task2 extends RecursiveTask<Integer> {
    private static final long serialVersionUID = 1L;
    private MatrixMock mock;
    private int start; // 查询起始行索引
    private int end; // 查询结束行索引
    private int num; // 要查找的数字
    public Task2(MatrixMock mock, int start, int end, int num) {
        this.mock = mock;
        this.start = start;
        this.end = end;
        this.num = num;
    }
    @Override
    protected Integer compute() {
        int result = 0;
        if (end - start < 100) { // 每个任务最多负责5行数据
            result = this.search();
            // 适合矩阵小的时候 查看对比结果
            // System.out.printf("%s,搜索起始行是:%s-%s,搜索结果是:%s\n",Thread.currentThread().getName(),start,end,result);
        } else { // 否则则拆分成两个子任务
            int mid = (end + start) / 2;
            Task2 task1 = new Task2(mock, start, mid, num);
            Task2 task2 = new Task2(mock, mid, end, num);
            invokeAll(task1, task2);
            try {
                result = task1.get() + task2.get(); // 两个结果相加,要想到 该框架的特性就是 递归
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        return result;
    }
    // 计算当前任务分配的行数
    private int search() {
        int result = 0;
        for (int i = start; i < end; i++) {
            int[] rows = mock.getRow(i);
            for (int row : rows) {
                if (num == row) {
                    result++;
                }
            }
        }
        return result;
    }
}
// 随机矩阵
class MatrixMock {
    private int[][] data;
    public MatrixMock(int size, int cols, int number) {
        data = new int[size][cols];
        Random random = new Random();
        int counter = 0;
        // 用随机数为矩阵赋值。每生成一个字,就用它跟要查找的数字比较,进行比较。如果一致,就用计数器加1
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < cols; j++) {
                data[i][j] = random.nextInt(10);
                if (data[i][j] == number) {
                    counter++;
                }
            }
        }
        // 用来验证多线程查找的正确性
        System.out.printf("在矩阵中找到了数字:%d,%d次\n", number, counter);
        // 测试的时候,可以放开此代码,能打印出 矩阵分布图。当然需要矩阵10 * 10 比较小的收,控制台才能装得下
        // for (int i = 0; i < data.length; i++) {
        // for (int j = 0; j < data[i].length; j++) {
        // System.out.printf(data[i][j] + " | ");
        // }
        // System.out.println("");
        // }
    }
    public int[] getRow(int row) {
        if (row >= 0 && row < data.length) {
            return data[row];
        }
        return null;
    }
}
thread_fork/join并发框架1的更多相关文章
- thread_fork/join并发框架2
		
转自 http://blog.csdn.net/mr_zhuqiang/article/details/48300229 三.使用异步方式 invokeAll(task1,task2); 是同步方式 ...
 - Java 7 Fork/Join 并行计算框架概览
		
应用程序并行计算遇到的问题 当硬件处理能力不能按摩尔定律垂直发展的时候,选择了水平发展.多核处理器已广泛应用,未来处理器的核心数将进一步发布,甚至达到上百上千的数量.而现在 很多的应用程序在运行在多核 ...
 - Java 并发系列之十:java 并发框架(2个)
		
1. Fork/Join框架 2. Executor框架 3. ThreadPoolExecutor 4. ScheduledThreadPoolExecutor 5. FutureTask 6. t ...
 - 深入理解Java并发框架AQS系列(一):线程
		
深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 一.概述 1.1.前言 重剑无锋,大巧不工 读j.u.c包下的源码,永远无法绕开的经典 ...
 - 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock)
		
一.前言 优秀的源码就在那里 经过了前面两章的铺垫,终于要切入正题了,本章也是整个AQS的核心之一 从本章开始,我们要精读AQS源码,在欣赏它的同时也要学会质疑它.当然本文不会带着大家逐行过源码(会有 ...
 - 协程并发框架gevent及其用法
		
gevent是python的一个并发框架,采用协程实现并发目的,用起来也非常简单 gevent的docs:http://www.gevent.org/contents.html 一个最简单的例子: i ...
 - Python 开源异步并发框架的未来
		
http://segmentfault.com/a/1190000000471602 开源 Python 是开源的,介绍的这几个框架 Twisted.Tornado.Gevent 和 tulip 也都 ...
 - Python开源异步并发框架
		
Python开源异步并发框架的未来 2014年3月30日,由全球最大的中文IT社区CSDN主办的“开源技术大会·” (Open Source Technology Conference ,简称OSTC ...
 - J.U.C并发框架
		
转载:http://itindex.net/detail/48869-j.u.c-%E6%A1%86%E6%9E%B6 J.U.C并发框架 作者:Doug Lea SUNY Oswego Oswego ...
 
随机推荐
- Windows 8 图标前面的勾选
			
http://bbs.pcbeta.com/viewthread-999730-1-1.html 不管是桌面的图标还是资源管理器中的图标之前都出现了一个小小的方框.选中图标的时候会自动勾选那个框,如果 ...
 - 用户管理 之 Linux 用户(user)和用户组(group)管理概述
			
一.理解Linux的单用户多任务,多用户多任务概念:Linux 是一个多用户.多任务的操作系统:我们应该了解单用户多任务和多用户多任务的概念: 1.Linux 的单用户多任务:单用户多任务:比如我们以 ...
 - How to get the Current Controller Name, Action, or ID in ASP.NET MVC
			
public static class HtmlRequestHelper { public static string Id(this HtmlHelper htmlHelper) { var ro ...
 - 【黑金原创教程】【FPGA那些事儿-驱动篇I 】连载导读
			
前言: 无数昼夜的来回轮替以后,这本<驱动篇I>终于编辑完毕了,笔者真的感动到连鼻涕也流下来.所谓驱动就是认识硬件,还有前期建模.虽然<驱动篇I>的硬件都是我们熟悉的老友记,例 ...
 - Source Insight 使用
			
1.括号配对高亮:“在前括号左侧,后括号左侧” 双击鼠标左键,可以选定匹配括号和其中内容(<>,(),L{R},[]之间) 2.让{ 和 } 不缩进:Options -> Docum ...
 - windows server 2003 ODBC数据源配置错误
			
1.ODBC 数据源链接失败,错误 :STATE hy000, 不能产生SSPI上下文, 2.文件服务器,TCP/IP协议属性中,DNS没有填写,填入DNS即可解决.
 - C#调用JAVA接口WSSE方式用WebClient方式
			
C#读取JAVA的WSSE接口的调用代码: 用webclient 方式: /// <summary> /// 调用java cxf ws_security加密的服务wcf客户端对应的加密类 ...
 - WorkbookDesigner mvc里面返回file
			
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
 - 解决Visual Studio 2010新建工程时出现『1>LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt』错误
			
VS2010在经历一些更新后,建立Win32 Console Project时会出"error LNK1123" 错误. 解决方案为: 第一步:将:项目|项目属性|配置属性|清 ...
 - git pull 指定版本
			
git init git remote add origin git@bitbucket.org:huashiyiqike/lstm-hf.git git pull origin master