并发框架实战

240 阅读4分钟

需求:

一个并发任务中心的框架,要求如下

  • 提高性能,采用多线程,屏蔽细节

  • 封装线程池和阻塞队列

  • 每个批量任务拥有自己的上下文环境

  • 需要一个并发安全的容器保存每个任务

  • 自动清除已完成和过期任务

  • 用户可以查询进度

如下两张图:

image-20200428164745716

image-20200428164737896

简单的类图设计如下

未命名文件

代码结构如下:

截屏2020-05-08 下午3.45.09

代码如下:

public class AppTest {

    private final static String JOB_NAME = "计算数值";
    private final static int JOB_LENGTH = 1000;

    //查询任务进度的线程
    private static class QueryResult implements Runnable {

        private PendingJobPool pool;

        public QueryResult(PendingJobPool pool) {
            super();
            this.pool = pool;
        }

        @Override
        public void run() {
            int i = 0;//查询次数
            while (i < 350) {
                List<TaskResult<String>> taskDetail = pool.getTaskResult(JOB_NAME);
                if (!taskDetail.isEmpty()) {
                    System.out.println(pool.getTaskProcess(JOB_NAME));
                    System.out.println(taskDetail);
                }
                SleepTools.ms(100);
                i++;
            }
        }

    }

    public static void main(String[] args) {
        MyTask myTask = new MyTask();
        //拿到框架的实例
        PendingJobPool pool = PendingJobPool.getInstance();
        //注册job
        pool.register(JOB_NAME, JOB_LENGTH, myTask, 1000 * 5);
        Random r = new Random();
        for (int i = 0; i < JOB_LENGTH; i++) {
            //依次推入Task
            pool.putTask(JOB_NAME, r.nextInt(1000));
        }
        Thread t = new Thread(new QueryResult(pool));
        t.start();
    }
}
public class MyTask implements ITaskProcesser<Integer, Integer> {

    @Override
    public TaskResult<Integer> execute(Integer data) {

        Random random = new Random();
        int flag = random.nextInt(500);
        SleepTools.ms(flag);
        if (flag <= 300) {
            Integer returnValue = data.intValue() + flag;
            return new TaskResult<Integer>(returnValue, TaskResultType.Success);
        } else if (flag > 301 && flag <= 400) {
            return new TaskResult<Integer>("Failure", -1, TaskResultType.Failure);
        } else {
            try {
                throw new RuntimeException("异常发生了!!");
            } catch (Exception e) {
                return new TaskResult<Integer>(e.getMessage(), -1, TaskResultType.Exception
                );
            }
        }

    }
}
public interface ITaskProcesser<T, R> {
    TaskResult<R> execute(T data);
}
public class JobInfo<R> {
    private AtomicInteger successCount;
    private AtomicInteger taskProcesserCount;
    private ITaskProcesser<?, ?> processer;
    private LinkedBlockingDeque<TaskResult<R>> queue;
    private int jobLength;
    private long expireTime;
    private String jobName;

    public JobInfo(int jobLength, long expireTime, ITaskProcesser<?, ?> processer, String jobName) {
        this.jobLength = jobLength;
        this.expireTime = expireTime;
        this.processer = processer;
        this.jobName = jobName;
        successCount = new AtomicInteger(0);
        taskProcesserCount = new AtomicInteger(0);
        queue = new LinkedBlockingDeque<TaskResult<R>>(jobLength);
    }

    public ITaskProcesser<?, ?> getTaskProcesser() {
        return processer;
    }

    public int getSuccessCount() {
        return successCount.get();
    }

    public int getTaskProcesserCount() {
        return taskProcesserCount.get();
    }

    public int getFailureCount() {
        return taskProcesserCount.get() - successCount.get();
    }

    public String getTotalProcess() {
        return "Success[" + successCount.get() + "]/Current["
                + taskProcesserCount.get() + "] Total[" + jobLength + "]";
    }


    public List<TaskResult<R>> getTaskResult() {
        TaskResult<R> taskResult;
        List<TaskResult<R>> list = new LinkedList<>();
        while ((taskResult = queue.pollFirst()) != null) {
            list.add(taskResult);
        }
        return list;
    }

    public void addTaskResult(TaskResult<R> taskResult, CheckJobPorcesser checkJobPorcesser) {
        if (taskResult.getType().equals(TaskResultType.Success)) {
            successCount.getAndIncrement();
        }
        taskProcesserCount.getAndIncrement();
        queue.addLast(taskResult);
        if (taskProcesserCount.get() == jobLength) {
            checkJobPorcesser.putJob(jobName, expireTime);
        }

    }
}
public class TaskResult<R> {
    private String reason;

    private R value;

    private TaskResultType type;


    public TaskResult(String reason, R value, TaskResultType type) {
        this.reason = reason;
        this.value = value;
        this.type = type;
    }

    public TaskResult(R value, TaskResultType type) {
        this.value = value;
        this.type = type;
    }

    public String getReason() {
        return reason;
    }

    public R getValue() {
        return value;
    }

    public TaskResultType getType() {
        return type;
    }

    @Override
    public String toString() {
        return "TaskResult{" +
                "reason='" + reason + '\'' +
                ", value=" + value +
                ", type=" + type +
                '}';
    }
}
public enum TaskResultType {


    Success,

    Failure,

    Exception;
}
public class CheckJobPorcesser {

    private static DelayQueue<ItemVo<String>> queue = new DelayQueue<ItemVo<String>>();

    private static class CheakJobHolder {
        public static CheckJobPorcesser checkJob = new CheckJobPorcesser();
    }

    public static CheckJobPorcesser getInstance() {
        return CheakJobHolder.checkJob;
    }

    public void putJob(String jobName, long expireTime) {
        ItemVo<String> itemVo = new ItemVo<>(expireTime, jobName);
        queue.offer(itemVo);
        System.out.println("Job[" + jobName + "已经放入了过期检查缓存,过期时长:" + expireTime);
    }

    public static class FecthJob implements Runnable {

        @Override
        public void run() {
            while (true) {
                try {
                    ItemVo<String> itemVo = queue.take();
                    String jobName = itemVo.getData();
                    PendingJobPool.getMap().remove(jobName);
                    System.out.println(jobName + " is out of date,remove from map!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static {
        Thread thread = new Thread(new FecthJob());
        thread.setDaemon(true);
        thread.start();
    }
}
public class ItemVo<T> implements Delayed {

    private long activeTime;//到期时间

    private T data;

    public ItemVo(long activeTime, T data) {
        //将传人的持续时间毫秒转化为纳秒,+当前时间纳秒 = 过期时刻
        this.activeTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(activeTime, TimeUnit.MILLISECONDS);
        this.data = data;
    }

    public long getActiveTime() {
        return activeTime;
    }

    public T getData() {
        return data;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(activeTime - System.nanoTime(), TimeUnit.NANOSECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        long l = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);
        return (l == 0) ? 0 : (l > 0) ? 1 : -1;
    }
}
public class PendingJobPool {
    private final int THREAD_NUM = Runtime.getRuntime().availableProcessors();
    private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(5000);
    private static ConcurrentHashMap<String, JobInfo<?>> jonInfoMap = new ConcurrentHashMap<>();
    private ExecutorService executor = new ThreadPoolExecutor(THREAD_NUM, THREAD_NUM, 60L, TimeUnit.SECONDS, queue);
    private static CheckJobPorcesser checkJobPorcesser = CheckJobPorcesser.getInstance();


    private static class PeningTask<T, R> implements Runnable {


        private JobInfo<R> jobInfo;
        private T data;

        public PeningTask(JobInfo<R> jobInfo, T data) {
            this.jobInfo = jobInfo;
            this.data = data;
        }

        @Override
        public void run() {
            R r = null;
            ITaskProcesser<T, R> taskProcesser = (ITaskProcesser<T, R>) jobInfo.getTaskProcesser();
            TaskResult<R> result = null;
            try {
                result = taskProcesser.execute(data);
                if (null == result) {
                    result = new TaskResult<R>("result is null", r, TaskResultType.Exception);
                }
                if (null == result.getType()) {
                    if (null == result.getReason()) {
                        result = new TaskResult<R>("reason is null", r, TaskResultType.Exception);
                    } else {
                        result = new TaskResult<R>("result is null,but reason" + result.getReason(), r, TaskResultType.Exception);
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
                result = new TaskResult<R>(e.getMessage(), r, TaskResultType.Exception);
            } finally {
                jobInfo.addTaskResult(result, checkJobPorcesser);
            }
        }
    }

    private static class PendingPoolHolder {
        private static PendingJobPool pendingJobPool = new PendingJobPool();
    }

    public static PendingJobPool getInstance() {
        return PendingPoolHolder.pendingJobPool;
    }

    public static ConcurrentHashMap<String, JobInfo<?>> getMap() {
        return jonInfoMap;
    }

    public <R> JobInfo<R> getJob(String jobName) {
        JobInfo<R> jobInfo = (JobInfo<R>) jonInfoMap.get(jobName);
        if (jobInfo == null) {
            throw new RuntimeException("是个非法任务");
        }
        return jobInfo;
    }

    public <T, R> void putTask(String jobName, T t) {
        JobInfo<R> job = getJob(jobName);
        PeningTask<T, R> task = new PeningTask<>(job, t);
        executor.execute(task);
    }

    public <R> void register(String jobName, int jobLength, ITaskProcesser<?, ?> processer, long expireTime) {
        JobInfo<R> jobInfo = new JobInfo(jobLength, expireTime, processer, jobName);
        if (jonInfoMap.putIfAbsent(jobName, jobInfo) != null) {
            throw new RuntimeException(jobName + "已经注册了!");
        }
    }

    public <R> List<TaskResult<R>> getTaskResult(String jobName) {
        JobInfo<R> job = getJob(jobName);
        return job.getTaskResult();
    }

    public <R> String getTaskProcess(String jobName) {
        JobInfo<R> job = getJob(jobName);
        return job.getTotalProcess();
    }

}