package com.wuban.tron.explore.fetch;

import com.wuban.tron.explore.util.ThreadPoolUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <core>线程池</core>
 *
 * @author sky
 * @date 2020/11/02
 */
@Slf4j
public class Executor {

    private static final int SIZE = 6;
    private final List<AbstractJob> jobList = new ArrayList<>();
    private final String name;
    private ThreadPoolExecutor pool;

    public Executor(final String name) {
        this.name = name;
        this.pool = new ThreadPoolExecutor(SIZE, SIZE * 2, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),
            new ExecutorThreadFactory());
        log.info("初始化线程池 name:{} coreSize:{} maxSize:{}", name, SIZE, 10);
    }

    public void execute(final AbstractJob r) {
        this.pool.execute(r);
        this.jobList.add(r);
    }

    public void shutdown() {
        this.jobList.forEach(job -> job.shutdown());
        ThreadPoolUtil.ensureShutdown(this.pool);
    }

    public void rebuild() {
        this.pool = new ThreadPoolExecutor(SIZE, SIZE * 2, 10L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(), new ExecutorThreadFactory());
    }

    /**
     * The match engine thread factory
     */
    private class ExecutorThreadFactory implements ThreadFactory {
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        ExecutorThreadFactory() {
            final SecurityManager s = System.getSecurityManager();
            this.group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
            this.namePrefix = "excutor-" + Executor.this.name + "-thread-";
        }

        @Override
        public Thread newThread(final Runnable r) {
            final Thread t = new Thread(this.group, r, this.namePrefix + this.threadNumber.getAndIncrement(), 0);
            if (t.isDaemon()) { t.setDaemon(false); }
            if (t.getPriority() != Thread.NORM_PRIORITY) { t.setPriority(Thread.NORM_PRIORITY); }
            return t;
        }
    }

}
