package com.ozs.da.utils;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @author 许明
 * on 2019/3/6.
 * @version 2.0.0
 * 线程池工具类
 */
public class ThreadPoolUtil {

    private static final Logger logger = LogManager.getLogger(ThreadPoolUtil.class);
    private static Map<String, ThreadPoolUtil> threadPoolMap = new HashMap<>();
    private String moduleName;// 模块名称
    private ExecutorService servicePool;//
    private ScheduledExecutorService schedulePool;

    private ThreadPoolUtil()
    {

    }
    /**
     *
     * @description 创建固定大小的线程池
     * @param moduleName
     *            线程池名称
     * @param poolSize
     *            线程池大小为 poolSize*CPU
     * @return
     */
    public static ThreadPoolUtil getTheadPool(String moduleName, int poolSize)
    {
        if (threadPoolMap.get(moduleName) != null)
        {
            logger.debug("获得moduleName[" + moduleName + "]线程池成功");
            return threadPoolMap.get(moduleName);
        }
        else
        {
            synchronized (ThreadPoolUtil.class)
            {
                if (threadPoolMap.get(moduleName) == null)
                {

                    ThreadPoolUtil threadPool = new ThreadPoolUtil();
                    threadPool.moduleName = moduleName;
                    int cpuNums = Runtime.getRuntime().availableProcessors();
                    ExecutorService servicePool = Executors.newFixedThreadPool(cpuNums * poolSize);
                    threadPool.setServicePool(servicePool);
                    threadPoolMap.put(moduleName, threadPool);
                    logger.debug("创建moduleName[" + moduleName + "]线程池 poolSize[" + cpuNums * poolSize + "]成功");
                    return threadPool;
                }
            }
        }
        return threadPoolMap.get(moduleName);
    }

    /**
     *
     * @description 创建不限大小的线程池
     * @param moduleName
     * @return
     */
    public static ThreadPoolUtil getTheadPool(String moduleName)
    {
        if (threadPoolMap.get(moduleName) != null)
        {
            logger.debug("获得moduleName[" + moduleName + "]不限大小线程池成功");
            return threadPoolMap.get(moduleName);
        }
        else
        {
            synchronized (ThreadPoolUtil.class)
            {
                if (threadPoolMap.get(moduleName) == null)
                {
                    ThreadPoolUtil threadPool = new ThreadPoolUtil();
                    threadPool.moduleName = moduleName;
                    ExecutorService servicePool = Executors.newCachedThreadPool();
                    threadPool.setServicePool(servicePool);
                    threadPoolMap.put(moduleName, threadPool);
                    logger.debug("创建moduleName[" + moduleName + "]不限大小线程池成功");
                    return threadPool;
                }
            }
        }
        return threadPoolMap.get(moduleName);
    }

    /**
     *
     * @description 创建任务调度类型的线程池
     * @param moduleName
     *            线程池名称
     * @param poolSize
     *            线程池大小为 poolSize*CPU
     * @return
     */
    public static ThreadPoolUtil getScheduleThreadPool(String moduleName, int poolSize)
    {
        if (threadPoolMap.get(moduleName) != null)
        {
            logger.debug("获得moduleName[" + moduleName + "]调度类型线程池成功");
            return threadPoolMap.get(moduleName);
        }
        else
        {
            synchronized (ThreadPoolUtil.class)
            {
                if (threadPoolMap.get(moduleName) == null)
                {

                    ThreadPoolUtil threadPool = new ThreadPoolUtil();
                    threadPool.moduleName = moduleName;
                    int cpuNums = Runtime.getRuntime().availableProcessors();
                    ScheduledExecutorService schedulePool = Executors.newScheduledThreadPool(cpuNums * poolSize);
                    threadPool.setSchedulePool(schedulePool);
                    threadPoolMap.put(moduleName, threadPool);
                    logger.debug("创建moduleName[" + moduleName + "]调度类型线程池 poolSize[" + cpuNums * poolSize + "]成功");
                    return threadPool;
                }
            }
        }
        return threadPoolMap.get(moduleName);
    }

    /**
     *
     * @description 线程池中添加Runnable类型
     * @param task
     */
    public void runTask(Runnable task)
    {
        threadPoolMap.get(moduleName).getServicePool().execute(task);
    }

    /**
     *
     * @description 线程池中添加Callable类型
     * @param task
     * @return
     */
    public Future<?> runTask(Callable<?> task)
    {
        return threadPoolMap.get(moduleName).getServicePool().submit(task);
    }

    /**
     *
     * @description 创建并执行在给定延迟后启用的一次性操作
     * @param run
     * @param delay
     * @param unit
     */
    public void scheduleTask(Runnable run, long delay, TimeUnit unit)
    {
        threadPoolMap.get(moduleName).getSchedulePool().schedule(run, delay, unit);
    }

    /**
     *
     * @description 创建并执行在给定延迟后启用的 ScheduledFuture
     * @param task
     * @param delay
     * @param unit
     */
    public void scheduleTask(Callable<?> task, long delay, TimeUnit unit)
    {
        threadPoolMap.get(moduleName).getSchedulePool().schedule(task, delay, unit);
    }

    /**
     *
     * @description 创建并执行一个在给定初始延迟后首次启用的定期操作，后续操作具有给定的周期
     * @param task
     * @param initialDelay
     * @param period
     * @param unit
     */
    public void scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit)
    {
        threadPoolMap.get(moduleName).getSchedulePool().scheduleAtFixedRate(task, initialDelay, period, unit);
    }

    /**
     *
     * @description 创建并执行一个在给定初始延迟后首次启用的定期操作，随后，在每一次执行终止和下一次执行开始之间都存在给定的延迟
     * @param task
     * @param initialDelay
     * @param delay
     * @param unit
     */
    public void scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit)
    {
        threadPoolMap.get(moduleName).getSchedulePool().scheduleWithFixedDelay(task, initialDelay, delay, unit);
    }

    /**
     * @description 批量提交任务，并行执行
     * @param tasks
     *            要执行的任务，这些任务需要实现Callable接口
     * @param timeout
     *            每个任务的超时时间,单位：毫秒
     * @return 每个任务执行完成后返回的结果集合
     */
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout)
    {
        List<Future<T>> futures = null;
        try
        {
            logger.debug("开始执行任务，要执行的任务数目为： " + tasks.size());
            long startTime = System.currentTimeMillis();
            if (timeout < 0)
            {
                futures = threadPoolMap.get(moduleName).getServicePool().invokeAll(tasks);
            }
            else
            {
                futures = threadPoolMap.get(moduleName).getServicePool().invokeAll(tasks, timeout, TimeUnit.MILLISECONDS);
                logger.debug("设定每个任务执行的超时时间为：" + timeout);
            }
            long endTime = System.currentTimeMillis();
            String time = String.valueOf(endTime - startTime);
            logger.debug("任务执行耗时： " + time + "毫秒");
        }
        catch (Exception e)
        {
            logger.error("并行执行任务出错", e);
        }
        return futures;

    }

    /**
     *
     * @description 关闭线程池（线程池的状态则立刻变成SHUTDOWN状态，不能再往线程池中添加任何任务）
     */
    public void shutDown()
    {
        ExecutorService servicePool = threadPoolMap.get(moduleName).getServicePool();
        if (servicePool != null)
        {
            servicePool.shutdown();
            logger.debug("线程池     Threadpool  name [" + moduleName + "] shuntdown success");
        }
        ScheduledExecutorService schedulePool = threadPoolMap.get(moduleName).getSchedulePool();
        if (schedulePool != null)
        {
            schedulePool.shutdown();
            logger.debug("线程池     Threadpool  name[" + moduleName + "] shuntdown success");
        }
        threadPoolMap.remove(moduleName);
    }

    /**
     *
     * @description 立即关闭线程池（线程池的状态立刻变成STOP状态，并试图停止所有正在执行的线程，不再处理还在池队列中等待的任务）
     */
    public void shutdownNow()
    {
        ExecutorService servicePool = threadPoolMap.get(moduleName).getServicePool();
        if (servicePool != null)
        {
            servicePool.shutdownNow();
            logger.debug("线程池     Threadpool  name [" + moduleName + "] shutdownNow success");
        }
        ScheduledExecutorService schedulePool = threadPoolMap.get(moduleName).getSchedulePool();
        if (schedulePool != null)
        {
            schedulePool.shutdownNow();
            logger.debug("线程池     Threadpool  name [" + moduleName + "] shutdownNow success");
        }
        threadPoolMap.remove(moduleName);
    }

    public ExecutorService getServicePool() {
        return servicePool;
    }

    public void setServicePool(ExecutorService servicePool) {
        this.servicePool = servicePool;
    }

    public ScheduledExecutorService getSchedulePool() {
        return schedulePool;
    }

    public void setSchedulePool(ScheduledExecutorService schedulePool) {
        this.schedulePool = schedulePool;
    }
}
