一 简介

并行设计模式属于设计优化的一部分,它是对一些常用的多线程结构的总结和抽象。与串行程序相比,并行程序的结构通常更为复杂,因此合理的使用并行模式在多线程开发中更具有意义,在这里主要介绍Future、Master-Worker和生产者-消费者模型

二 Future模式

Future模式有点类似于商品订单。比如在网购时,当看中某一件商品时,就可以提交订单,当订单处理完成后,在家等待商品送货上门即可。或者说更形象的,我们发送Ajax请求的时候,页面是异步的进行后台处理,用户无需一直等待请求的结果,可以继续浏览或操作其他内容。

public class Main {

	public static void main(String[] args) {
FutureClient futureClient = new FutureClient();
Date date = futureClient.request("date");
System.out.println("请求已经被处理...");
System.out.println("去做其他操作..."); System.out.println("结果为:" + date.getRequest());
} } public class FutureClient { public Date request(final String queryStr) {
//1.想要一个代理对象(Date接口的实现类)先返回给发送请求的客户端,告诉她请求已经被接收到,可以做其他事情
final FutureDate futureDate = new FutureDate();
//2.启动一个新的线程,去加载真实数据,传递给这个代理对象
new Thread(new Runnable() {
@Override
public void run() {
//3.这个新的线程可以去加载真实对象,然后传递给代理对象
RealDate realDate = new RealDate(queryStr);
futureDate.setRealDate(realDate);
}
}).start();;
return futureDate;
}
} public interface Date { String getRequest();
} public class FutureDate implements Date{
private RealDate realDate;
private Boolean isReady = false;
@Override
public synchronized String getRequest() {
while (!isReady) {
try {
//如果没有装载完毕,程序一直处于阻塞状态
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//装载好直接获取数据
return this.realDate.getRequest();
} public synchronized void setRealDate(RealDate realDate) {
while (isReady) {
//如果已经加载完毕,就直接返回
return;
}
//如果没有,就进行装载真实对象
this.realDate = realDate;
this.isReady = true;
//通知
notify();
}
} public class RealDate implements Date{
private String realDate;
public RealDate(String realDate) {
System.out.println("根据" + realDate + "进行查询,这是一个很耗时的操作...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("操作完毕,获取结果...");
this.realDate = "查询结果";
}
@Override
public String getRequest() {
// TODO Auto-generated method stub
return this.realDate;
}
}

运行结果:

请求已经被处理...

去做其他操作...

根据date进行查询,这是一个很耗时的操作...

操作完毕,获取结果...

结果为:查询结果

三 Master-Worker模式

Master-Worker模式是常用的并行设计模式。它的核心思想是系统由两类进程协作工作:Master进程和Worker进程。Master进程负责接收和分配任务,Worker进程负责处理子任务。当各个Worker进程处理完成后,会将结果返回给Master,由Master做归纳和总结。其好处是能将一个大任务分解成若干个小任务,并行执行,从而提高系统的吞吐量。

public class Task {

	private int id;
private String name;
private int price; public Task(int id, String name, int price) {
super();
this.id = id;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
} public class Master {
//1.有一个承装任务的集合ConcurrentLinkedQueue
private ConcurrentLinkedQueue<Task> workQueue = new ConcurrentLinkedQueue<>();
//2.使用普通的HashMap承装所有的Worker对象
private HashMap<String, Thread> workers = new HashMap<>();
//3.使用一个容器承装每一个Worker并发执行任务的结果集
private ConcurrentHashMap<String, Object> resultMap = new ConcurrentHashMap<>();
//4.构造方法
public Master(Worker worker, int workerCount) {
//每一个Worker对象都需要有Master的引用workQueue用于任务的领取,resultMap用于任务的提交
worker.setWorkerQueue(this.workQueue);
worker.setResultMap(this.resultMap);
for (int i = 1; i <= workerCount; i++) {
//key表示每个Worker的名字,value表示线程执行对象
this.workers.put("子节点" + Integer.toString(i), new Thread(worker));
}
}
//5.提交方法
public void submit(Task task) {
this.workQueue.add(task);
}
//6.需要执行方法,让所有Worker工作
public void execute() {
for(Map.Entry<String,Thread> entry : workers.entrySet()) {
System.out.println("Worker:" + entry.getKey() + "开始执行...");
entry.getValue().start();
}
}
//7.判断线程是否已经执行完毕
public boolean isComplete() {
for(Map.Entry<String,Thread> entry : workers.entrySet()) {
if(entry.getValue().getState() != Thread.State.TERMINATED) {
return false;
}
}
return true;
}
//8.返回结果集数据
public int getResult() {
int ret = 0;
for(Map.Entry<String,Object> entry : resultMap.entrySet()) {
ret += (Integer)entry.getValue();
}
return ret;
} } public class Worker implements Runnable{
private ConcurrentLinkedQueue<Task> workQueue;
private ConcurrentHashMap<String, Object> resultMap;
public void setWorkerQueue(ConcurrentLinkedQueue<Task> workQueue) {
this.workQueue = workQueue;
} public void setResultMap(ConcurrentHashMap<String, Object> resultMap) {
this.resultMap = resultMap;
}
@Override
public void run() {
while(true) {
Task input = this.workQueue.poll();
if(input == null) break;
//handle真正处理业务的方法
Object ouput = hanle(input);
this.resultMap.put(Integer.toString(input.getId()), ouput);
}
} private Object hanle(Task input) {
Object output = null;
try {
//表示处理业务的耗时,可能是数据的加工也可能是操作数据库
Thread.sleep(500);
output = input.getPrice();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return output;
}
} public class Main { public static void main(String[] args) {
//Master master = new Master(new Worker(), Runtime.getRuntime().availableProcessors());
//当前及其可用线程数
Master master = new Master(new Worker(), 20);
Random price = new Random();
for (int i = 0; i < 100 ; i++) {
Task t = new Task(i, "任务" + i, price.nextInt(1000));
master.submit(t);
}
master.execute();
long start = System.currentTimeMillis();
while(true) {
if(master.isComplete()) {
long end = System.currentTimeMillis();
int result = master.getResult();
System.out.println("最终结果:" + result + ",耗时:" + (end - start));
break;
}
}
}
}

运行结果:

Worker:子节点8开始执行...

Worker:子节点7开始执行...

Worker:子节点9开始执行...

Worker:子节点16开始执行...

Worker:子节点17开始执行...

Worker:子节点2开始执行...

Worker:子节点18开始执行...

Worker:子节点1开始执行...

Worker:子节点19开始执行...

Worker:子节点4开始执行...

Worker:子节点12开始执行...

Worker:子节点3开始执行...

Worker:子节点13开始执行...

Worker:子节点6开始执行...

Worker:子节点14开始执行...

Worker:子节点5开始执行...

Worker:子节点15开始执行...

Worker:子节点20开始执行...

Worker:子节点10开始执行...

Worker:子节点11开始执行...

最终结果:50179,耗时:2505

三 生产者-消费者模式

生产者和消费者也是一个非常经典的多线程模式,我们在实际开发中应用非常广泛的思想理念。在生产-消费者模式中:通常由两类线程,即若干个生产者的线程和若干个消费者的线程。生产者线程负责提交用户请求,消费者线程则负责具体处理生产者提交的任务,在生产者和消费者之间通过共享内存缓存区进行通信。

MQ(Message Queue)消息队列中间件使用了生产者-消费者模式

public class Data {

	private String id;
private String data;
public Data(String id, String data) {
super();
this.id = id;
this.data = data;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
} } public class Provider implements Runnable{ private LinkedBlockingQueue<Data> queue;
private AtomicInteger count = new AtomicInteger(0);
private volatile boolean isRunning = true;
private Random random = new Random(); public Provider(LinkedBlockingQueue<Data> queue) {
super();
this.queue = queue;
}
@Override
public void run() {
while(this.isRunning) {
try {
Thread.sleep(random.nextInt(1000));
int id = count.incrementAndGet();
Data data = new Data(Integer.toString(id), "数据" + id);
System.out.println("当前生产线程:" + Thread.currentThread().getName() + ",获取了数据,id为:" + id + ",进行装载到公共缓冲区...");
if(!this.queue.offer(data, 2, TimeUnit.SECONDS)) {
System.out.println("提交缓冲区失败...");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void stop() {
this.isRunning = false;
}
} public class Consumer implements Runnable{ private LinkedBlockingQueue<Data> queue; public Consumer(LinkedBlockingQueue<Data> queue) {
super();
this.queue = queue;
}
@Override
public void run() {
while(true) {
try {
Data data = this.queue.take();
Thread.sleep(1000);
System.out.println("当前消费线程为:" + Thread.currentThread().getName() + ",消费成功,消费数据为id:" + data.getId());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} public class Main { public static void main(String[] args) {
//内存缓冲区
LinkedBlockingQueue<Data> queue = new LinkedBlockingQueue<>();
//生产者
Provider p1 = new Provider(queue);
Provider p2 = new Provider(queue);
Provider p3 = new Provider(queue);
//消费者
Consumer c1 = new Consumer(queue);
Consumer c2 = new Consumer(queue);
Consumer c3 = new Consumer(queue); //创建线程池运行,这是一个缓存的线程池,可以创建无穷大的线程,没有任务的时候不创建线程,空闲线程存活时间为60s(默认)
ExecutorService cachePool = Executors.newCachedThreadPool();
cachePool.execute(p1);
cachePool.execute(p2);
cachePool.execute(p3);
cachePool.execute(c1);
cachePool.execute(c2);
cachePool.execute(c3); try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
p1.stop();
p2.stop();
p3.stop();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //cachePool.shutdown();
} }

运行结果:

当前生产线程:pool-1-thread-3,获取了数据,id为:1,进行装载到公共缓冲区...

当前生产线程:pool-1-thread-1,获取了数据,id为:1,进行装载到公共缓冲区...

当前生产线程:pool-1-thread-3,获取了数据,id为:2,进行装载到公共缓冲区...

当前生产线程:pool-1-thread-2,获取了数据,id为:1,进行装载到公共缓冲区...

当前生产线程:pool-1-thread-1,获取了数据,id为:2,进行装载到公共缓冲区...

当前消费线程为:pool-1-thread-4,消费成功,消费数据为id:1

当前消费线程为:pool-1-thread-6,消费成功,消费数据为id:1

当前生产线程:pool-1-thread-1,获取了数据,id为:3,进行装载到公共缓冲区...

当前生产线程:pool-1-thread-2,获取了数据,id为:2,进行装载到公共缓冲区...

当前生产线程:pool-1-thread-3,获取了数据,id为:3,进行装载到公共缓冲区...

当前消费线程为:pool-1-thread-5,消费成功,消费数据为id:2

当前消费线程为:pool-1-thread-4,消费成功,消费数据为id:1

当前消费线程为:pool-1-thread-6,消费成功,消费数据为id:2

当前生产线程:pool-1-thread-1,获取了数据,id为:4,进行装载到公共缓冲区...

当前生产线程:pool-1-thread-2,获取了数据,id为:3,进行装载到公共缓冲区...

当前生产线程:pool-1-thread-3,获取了数据,id为:4,进行装载到公共缓冲区...

当前生产线程:pool-1-thread-3,获取了数据,id为:5,进行装载到公共缓冲区...

当前生产线程:pool-1-thread-1,获取了数据,id为:5,进行装载到公共缓冲区...

当前消费线程为:pool-1-thread-5,消费成功,消费数据为id:3

当前生产线程:pool-1-thread-3,获取了数据,id为:6,进行装载到公共缓冲区...

当前生产线程:pool-1-thread-2,获取了数据,id为:4,进行装载到公共缓冲区...

当前消费线程为:pool-1-thread-4,消费成功,消费数据为id:2

当前消费线程为:pool-1-thread-6,消费成功,消费数据为id:3

当前生产线程:pool-1-thread-1,获取了数据,id为:6,进行装载到公共缓冲区...

当前消费线程为:pool-1-thread-5,消费成功,消费数据为id:4

当前消费线程为:pool-1-thread-4,消费成功,消费数据为id:3

当前消费线程为:pool-1-thread-6,消费成功,消费数据为id:4

当前消费线程为:pool-1-thread-5,消费成功,消费数据为id:5

当前消费线程为:pool-1-thread-4,消费成功,消费数据为id:5

当前消费线程为:pool-1-thread-6,消费成功,消费数据为id:6

当前消费线程为:pool-1-thread-5,消费成功,消费数据为id:4

当前消费线程为:pool-1-thread-4,消费成功,消费数据为id:6

多线程的设计模式:Future、Master-Worker的更多相关文章

  1. 多线程的设计模式--Future模式,Master-Worker模式,生产者-消费者模式

    代码示例: public interface Data { String getRequest(); } public class FutureData implements Data{ privat ...

  2. 多线程集成设计模式--future模式

    多线程开发可以更好的发挥多核cpu性能,常用的多线程设计模式有:Future.Master-Worker.Guard Susperionsion 一.什么是Future模型: 该模型是将异步请求和代理 ...

  3. 多线程设计模式 - Future模式

    Future模式是多线程开发中非常常见的一种设计模式,它的核心思想是异步调用.这类似我们日常生活中的在线购物流程,带在购物网看着一件商品时可以提交表单,当订单完成后就可以在家里等待商品送货上门.或者说 ...

  4. 13.多线程设计模式 - Future模式

    多线程设计模式 - Future模式 并发设计模式属于设计优化的一部分,它对于一些常用的多线程结构的总结和抽象.与串行相比并行程序结构通常较为复杂,因此合理的使用并行模式在多线程并发中更具有意义. 1 ...

  5. 多线程集成设计模式--MasterWorker模式讲解(一)

    Master-Worker模式是常用的并行模式之一,它的核心思想是,系统有两个进程协作工作:Master进程,负责接收和分配任务:Worker进程,负责处理子任务.当Worker进程将子任务处理完成后 ...

  6. Java多线程_Master-Worker设计模式

    Master-Worker模式是常用的并行模式之一,它的核心思想是:系统由Master进程和Worker进程两类进程协同工作,Master负责接收和分配任务,Wroker负责处理子任务.当各个Work ...

  7. 多线程设计模式 - Future模式之JAVA原生实现

    在之前一篇博客中介绍了Future设计模式的设计思想以及具体实现,今天我们来讲一下使用JDK原生的包如何实现. JDK内置的Future主要使用到了Callable接口和FutureTask类. Ca ...

  8. java多线程系列13 设计模式 Future 模式

    Future 模式 类似于ajax请求  页面异步的进行后台请求 用户无需等待请求的结果 就可以继续浏览或者操作 核心就是:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑 ...

  9. java多线程12设计模式

    1.Single Threaded Execution Pattern(单线程运行模式) 2.Immutable Pattern(一成不变的模式) 3.Guarded Suspension Patte ...

随机推荐

  1. 一、创建且运行JPA工程

    1. 创建JPA 工程 (1)选择创建 JPA Project,注意不是Java Project (2)JPA version选择 2.0 (3)选择用户库,否则会出现 At least one us ...

  2. jdbcTemplate查询结果为对象list

    RowMapper<WmsExpensesSettleEntity> rowMapper1=new BeanPropertyRowMapper<WmsExpensesSettleEn ...

  3. SQL Server 管理套件(SSMS)

    SQL Server 管理套件(SSMS) 当您按照之前章节的步骤顺利安装完 SQL Server 2014 后,要做的第一件事就是需要打开 SQL Server 管理套件,并且要知道怎样去使用它. ...

  4. UVa 11384 (推公式+递归)

    题目: 给你1到n,现在让你将每个数变成0,每一步操作可以选取任意数一起减去一个整数,减完了不能为负数!问你最少需要几步? 巨水的题,然而为什么要写博客呢?提醒自己要记得递归函数,不要傻傻的开数组硬比 ...

  5. 在ios微信中提交form,php端收不到参数的问题

    今天做h5页面时,微信浏览器中提交form表单,发现php端收不到post过来的参数,在普通浏览器中可以,安卓微信也可以,$_POST,$_GET,$_REQUEST等方式都不行. 后来,把form表 ...

  6. CDN技术之-介绍

    “第一公里”是指万维网流量向用户传送的第一个出口,是网站服务器接入互联网的链路所能提供的带宽.这个带宽决定了一个网站能为用户提供的访问速度和并发访问量.如果业务繁忙,用户的访问数越多,拥塞越严重,网站 ...

  7. nginx调优配置

    nginx调优配置 user www www; #工作进程:数目.根据硬件调整,通常等于CPU数量或者2倍于CPU. worker_processes 8; worker_cpu_affinity 0 ...

  8. sqlserver2008新建查询,表名下出现红波浪线,显示“表名无效”,但仍然可以查询得到结果(转)

    转:http://zhidao.baidu.com/link?url=82Xf_uK9VgIeYM_1kczmvKhiEQKLCqhN4_Tfe_cvriqkeP7Wggy5D60VTnMxFREwz ...

  9. Angular 2 技能图谱skill-map

    # Angular 2 技能图谱 ## 模块 ### 自定义模块 - 根模块 - 特性模块 - 共享模块 - 核心模块 ### 内置模块 - ApplicationModule 模块 - Common ...

  10. (14)C++ 代码重用

    valarray<,,,, };//进行高速的数字计算 int a= val.size();//返回包含元素个数 int b= val.sum();//元素总和 int c= val.max() ...