多线程实现数列的累加

背景

今天实现一下利用多线程进行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只有两个核,所以大量时间都用在了保持同步上,但如果在大型服务器上运行此模型,时间应该会节省不少。

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值