首先我们看如下这个问题:
我们需要计算1 ~ 100 的立方和。
很简单是吧
@Test
public void cube() {
long sum = 0;
long max = 100L;
for (int i = 1; i <= max; i++) {
sum += i * i * i;
}
System.out.println("结果为" + sum);
}
我们来看下运行情况
运行时间1ms,这无法说明问题,我们给代码中加入模拟业务逻辑代码再次运行。
@Test
public void cubeBusiness() throws InterruptedException {
long sum = 0;
long max = 100L;
for (int i = 1; i <= max; i++) {
// 模拟业务逻辑
Thread.sleep(30);
sum += i * i * i;
}
System.out.println("结果为" + sum);
}
运行时间3s。
Master-Worker模式
接下来我们使用 Master-Worker
并发模型来优化我们的代码。
首先简单的介绍下什么是 Master-Worker
并发模型。
废话不多说,直接贴图。
简单的说,就是将串行执行的代码,用分治的思想拆分成许多任务,用并行的方式去执行这些任务,最后将结果进行整理输出。
Master-Worker 模式主要角色
角色 | 作用 |
---|---|
Worker | 用于实际处理一个任务 |
Master | 用于任务的分配和最终结果的合成 |
Main | 启动系统,调度开启Master |
Master-Worker 代码实现
接下来给出 Master-Worker 简易框架的实现代码
- Master
package sumofcube;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
/**
* @Author suxiaoxiao
* @Date 2019/8/11 14:01
* @Version 1.0
*/
public class Master {
/**
* 任务队列
*/
protected Queue<Object> workQueue = new ConcurrentLinkedDeque<>();
/**
* Worker 线程队列
*/
protected Map<String, Thread> threadMap = new HashMap<>();
/**
* 子任务处理结果集
*/
protected Map<String, Object> resultMap = new ConcurrentHashMap<>();
/**
* 是否所有的子任务都结束了
*/
public boolean isComplete() {
for (Map.Entry<String, Thread> entry : threadMap.entrySet()) {
if (entry.getValue().getState() != Thread.State.TERMINATED) {
return false;
}
}
return true;
}
/**
*
* @param worker 具体任务
* @param CountWorker worker数量
*/
public Master(Worker worker, int CountWorker) {
worker.setWorkerQueue(workQueue);
worker.setResultMap(resultMap);
for (int i = 0; i < CountWorker; i++) {
threadMap.put(Integer.toString(i), new Thread(worker, Integer.toString(i)));
}
}
/**
* 提交一个任务
* @param job
*/
public void submit(Object job) {
workQueue.add(job);
}
/**
* 返回结果集
* @return
*/
public Map<String, Object> getResultMap() {
return resultMap;
}
/**
* 开启所有Worker线程,进行处理。
*/
public void execute() {
for (Map.Entry<String, Thread> entry : threadMap.entrySet()) {
entry.getValue().start();
}
}
}
因为是多线程模型,所以要考虑到线程安全问题,在Master中我们使用 ConcurrentLinkedDeque
来控制获取子任务的线程安全,使用 ConcurrentHashMap
保证最终结果的线程安全。
- Worker
package sumofcube;
import java.util.Map;
import java.util.Queue;
/**
* @Author suxiaoxiao
* @Date 2019/8/11 14:11
* @Version 1.0
*/
public class Worker implements Runnable {
/**
* 任务队列,取的子任务用。
*/
protected Queue<Object> workerQueue;
/**
* 子任务处理结果集
*/
protected Map<String, Object> resultMap;
public void setWorkerQueue(Queue<Object> workerQueue) {
this.workerQueue = workerQueue;
}
public void setResultMap(Map<String, Object> resultMap) {
this.resultMap = resultMap;
}
// 由具体的实现类去实现具体执行的任务
public Object handler(Object input) {
return input;
}
@Override
public void run() {
while (true) {
// 从任务队列中,获取子任务
Object input = workerQueue.poll();
if (input == null) {
break;
}
Object re = null;
// 处理子任务
re = handler(input);
// 将处理结果写入结果集
resultMap.put(Integer.toString(input.hashCode()), re);
}
}
}
- Worker 对象应用层的实现代码,为了跟串行方法作对比,我们模拟实际开发中的业务处理。
package sumofcube;
/**
* @Author suxiaoxiao
* @Date 2019/8/11 14:32
* @Version 1.0
*/
public class PlusWorker extends Worker {
@Override
public Object handler(Object input) {
Integer value = (Integer) input;
try {
// 模拟复杂的业务逻辑
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
return value * value * value;
}
}
- 调用方法
@Test
public void cubeMasterWorkerTest() {
// 这里我们启动 12 个线程
Master master = new Master(new PlusWorker(), 12);
// 提交 100 个任务
long max = 100L;
for (int i = 1; i <= max; i++) {
master.submit(i);
}
master.execute();
// 最终结果
long result = 0L;
Map<String, Object> resultMap = master.getResultMap();
while (true) {
Set<String> keys = resultMap.keySet();
String key = null;
for (String keyValue : keys) {
key = keyValue;
break;
}
Integer i = null;
if (key != null) {
i = (Integer)resultMap.get(key);
resultMap.remove(key);
}
if (i != null) {
result += i;
}
if (resultMap.size() <= 0 && master.isComplete()) {
break;
}
}
System.out.println("结果为" + result);
}
我们看下对比结果
- 串行执行的结构
- 使用
Master-Worker
并发模型优化后的结果
结果显而易见。