背景
今天实现一下利用多线程进行1~50的四次方累加。主要参考此文章
构思
主要是三部分:客户端、调度者、工作者
客户端就是MainActivity,用来构造调度者,向调度者提交任务,以及从调度者那里获取结果集,在工作者计算的时候就获取已经算好的结果,进行累加
调度者是Master,用来构造工作者,向任务队列提交任务,启动工作者
工作者是worker,是一个队列,用来真正的计算,并向结果集里添加结果
实现
工作者
先实现工作者的父类,里面实现了run()方法,拥有任务队列和结果队列,这两者都要线程安全
package applicationmanager.com.example.a123;
import java.util.concurrent.ConcurrentLinkedQueue;
public abstract class BaseWorker implements Runnable{
protected ConcurrentLinkedQueue<Object> mTasks ;
ConcurrentLinkedQueue<Object> mResults ;
public void setTasks(ConcurrentLinkedQueue<Object> mTasks) {
this.mTasks = mTasks;
}
public void setResults(ConcurrentLinkedQueue<Object> results) {
this.mResults = results;
}
public abstract int work();
@Override
public void run() {
while (true) {
int workResult = work();
if (workResult > 0) {
mResults.add(workResult);
} else if (workResult == Constants.ERROR_QUEUE_EMPTY
|| workResult == Constants.ERROR_NULL_NODE) {
return;
}
}
}
}
再实现子类,真正执行计算的worker
package applicationmanager.com.example.a123;
public class CalculateWorker extends BaseWorker {
@Override
public int work() {
if (mTasks == null || mTasks.isEmpty()) {
return Constants.ERROR_QUEUE_EMPTY;
}
Object work = mTasks.poll();
if (work == null) {
return Constants.ERROR_NULL_NODE;
}
if (work instanceof Integer) {
int number = (Integer)work;
return number * number * number * number;
}
return Constants.ERROR_WRONG_TYPE;
}
}
从队首取元素,进行计算。如果任务队列是空,或者获取的头结点也是空,说明任务队列空了,但还是用不同的错误码表示。run()方法里根据错误码,决定直接返回还是把结果添加到结果队列里
调度者
调度者和工作者共享任务队列和结果队列,和客户端共享结果队列,并负责向任务队列里提交任务,启动工作者队列,返回结果队列,以及工作状态的检测。据此,可以写出如下代码
package applicationmanager.com.example.a123;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentLinkedQueue;
public class Master {
// 根据cpu核数,创建worker线程
private LinkedList<Thread> workers = new LinkedList<>();
// 任务列表
private ConcurrentLinkedQueue<Object> tasks = new ConcurrentLinkedQueue<>();
// 结果队列
private ConcurrentLinkedQueue<Object> results = new ConcurrentLinkedQueue<>();
public Master(int coresNumber) {
if (coresNumber <= 0) {
return;
}
for (int i = 0; i < coresNumber; i++) {
CalculateWorker worker = new CalculateWorker();
workers.add(new Thread(worker));
worker.setTasks(tasks);
worker.setResults(results);
}
}
public void beginWork() {
for (int i = 0; i < workers.size(); i++) {
workers.get(i).start();
}
}
public ConcurrentLinkedQueue<Object> getResults() {
return results;
}
public void addTask(Object task) {
if (task != null) {
tasks.add(task);
}
}
public boolean isComplete() {
if (workers == null || workers.size() <= 0) {
return true;
}
boolean isOver = true;
for (int i = 0; i < workers.size(); i++) {
Thread worker = workers.get(i);
if (worker != null && worker.getState() != Thread.State.TERMINATED) {
isOver = false;
}
}
return isOver;
}
}
客户端
客户端用来给调度者提供任务,以及异步地从结果集里取出结果进行累加。据此,相关代码片段如下
int total = 0;
int coreNumber = Runtime.getRuntime().availableProcessors();
Logger.logger("cpu核数:" + coreNumber);
master = new Master(coreNumber);
for (int i = 1; i < 50; i++) {
master.addTask(i);
}
long beginTime = System.currentTimeMillis();
master.beginWork();
ConcurrentLinkedQueue<Object> results = master.getResults();
while ((results != null && !results.isEmpty()) || !master.isComplete()) {
Object obj = results.poll();
if (obj != null && obj instanceof Integer) {
int result = (Integer) obj;
total += result;
}
}
long overTime = System.currentTimeMillis();
Logger.logger("用时:" + (int) (overTime - beginTime));
运行结果
结果如图所示
用于模拟机的cpu只有两个核,所以大量时间都用在了保持同步上,但如果在大型服务器上运行此模型,时间应该会节省不少。
有问题欢迎在评论区讨论。