多线程实现数列的累加

背景

今天实现一下利用多线程进行1~50的四次方累加。主要参考马剑威的公众号文章

 

https://mp.weixin.qq.com/s?__biz=MzAwOTUyNzI3Ng==&mid=2652073464&idx=1&sn=0644bb05245147456957dbba09fc16e3&chksm=80b9877bb7ce0e6d7c7fc56314e78c240b9547e0da782c576ba23b08688c5740c9e191f39499&scene=0&subscene=131&ascene=7&devicetype=android-24&version=2607033a&nettype=WIFI&abtest_cookie=BQABAAgACgALABIAFAAFAJ2GHgAllx4AV5keAJuZHgCimR4AAAA%3D&lang=zh_CN&pass_ticket=6EKBnISZNpVloiFRSBIO%2BdIqQtbYBf%2BaKxjpjiXaggawi7eIghZ5mdtqqywtANGH&wx_header=1

 

构思

主要是三部分:客户端、调度者、工作者

客户端就是MainActivity,用来构造调度者,向调度者提交任务,以及从调度者那里获取结果集,在工作者计算的时候就获取已经算好的结果,进行累加

调度者是Master,用来构造工作者,向任务队列提交任务,启动工作者

工作者是worker,是一个队列,用来真正的计算,并向结果集里添加结果

 

实现

工作者

先实现工作者的父类,里面实现了run()方法,拥有任务队列和结果队列,这两者都要线程安全

package applicationmanager.com.example.a123;

import java.util.concurrent.ConcurrentLinkedQueue;

public abstract class BaseWorker implements Runnable{
    protected ConcurrentLinkedQueue mTasks ;
    ConcurrentLinkedQueue mResults ;

    public void setTasks(ConcurrentLinkedQueue mTasks) {
        this.mTasks = mTasks;
    }

    public void setResults(ConcurrentLinkedQueue 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 workers = new LinkedList<>();

    // 任务列表
    private ConcurrentLinkedQueue tasks = new ConcurrentLinkedQueue<>();

    // 结果队列
    private ConcurrentLinkedQueue 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 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 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)); 
  

 

运行结果

结果如图所示

多线程实现数列的累加_第1张图片

用于模拟机的cpu只有两个核,所以大量时间都用在了保持同步上,但如果在大型服务器上运行此模型,时间应该会节省不少。

有问题欢迎在评论区讨论。

你可能感兴趣的:(异步与线程)