并发编程16

并发编程16

ThreadPoolExcutor源码

关闭线程池

shutdown()

public void shutdown() {
    
    
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
    
    
            // 是否允许shutdown
            checkShutdownAccess();
            // 设置成shutdown状态
            advanceRunState(SHUTDOWN);
            // 不会打断正在执行的任务
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
    
    
            mainLock.unlock();
        }
        tryTerminate();
    }

shutdownNow()

public List<Runnable> shutdownNow() {
    
    
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
    
    
            checkShutdownAccess();
            advanceRunState(STOP);
            interruptWorkers();
            // 取出队列中的任务
            tasks = drainQueue();
        } finally {
    
    
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

常规线程池

1.测试存活的线程池数目

  • private static void method1() {
          
          
        threadPoolExecutor = new ThreadPoolExecutor(1,2,
                                                    3, TimeUnit.SECONDS,
                                                    new ArrayBlockingQueue<>(5));
    
    
        for (int i = 0; i <6 ; i++) {
          
          
            //这里永远只有一个线程在工作?
            // 并发编程的艺术 -----因为队列能够存放的下任务所以不会启用空闲线程
            threadPoolExecutor.execute(()->{
          
          
                log.debug("worker thread size[{}]",threadPoolExecutor.getPoolSize());
            });
        }
    }
    

2.队列数远大于任务数,无核心线程,最大线程很大,此时任务是马上执行,还是不会

  • public static void main(String[] args) throws InterruptedException, ExecutionException {
          
          
        threadPoolExecutor = new ThreadPoolExecutor(0,1000,
                                                    3, TimeUnit.SECONDS,
                                                    new ArrayBlockingQueue<>(10000));
    
    
        for (int i = 0; i <6 ; i++) {
          
          
            //执行这个任务的线程是什么线程? 并不核心线程?
            /**
                 * 核心线程和空闲线程测区别?
                 * 1、空闲线程可能会销毁(存活时间)
                 * 2、核心线程是不会销毁的
                 *  50
                 * 线程池是如何保证核心线程不会被销毁的---->空闲线程数为什么会销毁
                 */
            threadPoolExecutor.execute(() -> {
          
          
                log.debug("worker thread size[{}]", threadPoolExecutor.getPoolSize());
            });
    
    
        }
    
    
    }
    
  • 队列数远大于任务数,无核心线程,最大线程很大,此时任务是马上执行,还是不会?

    • 按道理应该是不会,因为队列没有满,会一直往队列中添加,此时都没有创建空闲线程,哪来的线程执行任务?但是模拟后,发现执行了,所以执行这些任务的线程是什么线程?
    • 核心线程和空闲线程的区别—是否会被销毁

threadPoolExecutor.execute()

execute

  • public void execute(Runnable command) {
          
          
        if (command == null)
            throw new NullPointerException();
        /*
             * Proceed in 3 steps:
             *
             * 1. If fewer than corePoolSize threads are running, try to
             * start a new thread with the given command as its first
             * task.  The call to addWorker atomically checks runState and
             * workerCount, and so prevents false alarms that would add
             * threads when it shouldn't, by returning false.
             *
             * 2. If a task can be successfully queued, then we still need
             * to double-check whether we should have added a thread
             * (because existing ones died since last checking) or that
             * the pool shut down since entry into this method. So we
             * recheck state and if necessary roll back the enqueuing if
             * stopped, or start a new thread if there are none.
             *
             * 3. If we cannot queue task, then we try to add a new
             * thread.  If it fails, we know we are shut down or saturated
             * and so reject the task.
             */
        int c = ctl.get();
        // workerCountOf 获取工作线程数量
        // 当核心线程数没满时走这里
        if (workerCountOf(c) < corePoolSize) {
          
          
            // addWorker
            // HashSet<Worker> workers是存放任务的集合
            // Worker是任务,同时这个类本身也是一个线程
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        // 当超过核心线程数了
        // 检查状态,并往阻塞队列中添加任务
        if (isRunning(c) && workQueue.offer(command)) {
          
          
            // 入队成功,再次检查状态
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                // 核心线程如果有,
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }
    

addWorker

  • private boolean addWorker(Runnable firstTask, boolean core) {
          
          
        retry:
        for (;;) {
          
          
            int c = ctl.get();
            int rs = runStateOf(c);
    
            // Check if queue empty only if necessary.
            // 检查状态
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;
    		
            for (;;) {
          
          
                int wc = workerCountOf(c);
                // 判断线程数量
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                // 改变工作线程数量
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
    
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
          
          
            // 把传进来的任务实例化
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
          
          
                // 加锁
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
          
          
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());
    				
                    // 判断线程池是否被关闭
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
          
          
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        // 把工作线程放到线程池中
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
          
          
                    mainLock.unlock();
                }
                // 启动任务
                if (workerAdded) {
          
          
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
          
          
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }
    

runWorker

  • final void runWorker(Worker w) {
          
          
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
          
          
            // 执行完第一个任务后,继续去取任务
            while (task != null || (task = getTask()) != null) {
          
          
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
          
          
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
          
          
                        task.run();
                    } catch (RuntimeException x) {
          
          
                        thrown = x; throw x;
                    } catch (Error x) {
          
          
                        thrown = x; throw x;
                    } catch (Throwable x) {
          
          
                        thrown = x; throw new Error(x);
                    } finally {
          
          
                        afterExecute(task, thrown);
                    }
                } finally {
          
          
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
          
          
            processWorkerExit(w, completedAbruptly);
        }
    }
    

getTask

  • private Runnable getTask() {
          
          
        boolean timedOut = false; // Did the last poll() time out?
    
        for (;;) {
          
          
            int c = ctl.get();
            int rs = runStateOf(c);
    
            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
          
          
                decrementWorkerCount();
                return null;
            }
    
            int wc = workerCountOf(c);
    
            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
    
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
          
          
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }
    
            try {
          
          
                // 核心线程不会销毁
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
          
          
                timedOut = false;
            }
        }
    }
    
  • 核心线程—addWorker(command, true) 取队列任务是通过take方法

  • 空闲线程—addWorker(null, false),没有把任务传给他,而是从队列中去取,是通过poll方法取

  • 线程池是如何保证核心线程不会被销毁的---->空闲线程数为什么会销毁?

  • excute()
      |
      V
    判断任务是否是null   --(T)-> NullPointerException
      |
      F
      |
      V
    获取工作的线程数量
      |
      V
    工作线程数量小于核心线程数量 --F-> 添加到队列 --T-> 判断线程状态 -!running-> reject
      |                               |              |
      T                               F            running
      |                               |              |
      v                               V              V
    addWordk1                     addWorker3     工作线程是否为0
      |                                              |
      |                                              T
      |                                              |
      V                                              V
    实例化一个核心线程                                addWorker2
                                                     |
                                                     |
                                                     |
                                                     V
                                                   实例化一个空闲线程
    

定时任务

Excutors.newScheduledThreadPool()

1.延迟3秒执行

  • 可以对任务执行时间做延迟(第一次执行之前)

  • public static void executeTask(){
          
          
        log.debug("start---task1");
    
        scheduledExecutorService.schedule(()->{
          
          
            executeTask();
        },3, TimeUnit.SECONDS);
    
    }
    

2.nacos心跳机制

  • newScheduledThreadPool里面再套一个newScheduledThreadPool

  • static ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
    public static void executeTask(){
          
          
        log.debug("start---task1");
    
        scheduledExecutorService.schedule(()->{
          
          
            executeTask();
        },3, TimeUnit.SECONDS);
    
    }
    
    private static void executeTask() {
          
          
        
        log.debug("main start");
        scheduledExecutorService.schedule(()->{
          
          
            executeTask();
        },3, TimeUnit.SECONDS);
    }
    

3.定时每隔相同时间执行scheduleAtFixedRate

  • //period 是包含在线程的执行时间当中的
    private static void atFixedRate() {
          
          
        scheduledExecutorService = Executors.newScheduledThreadPool(2);
        scheduledExecutorService.scheduleAtFixedRate(()->{
          
          
            log.debug("start---task1");
            try {
          
          
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
          
          
                e.printStackTrace();
            }
        },2,1,TimeUnit.SECONDS);
    }
    
  • 这个方法是固定每秒执行一次,但是任务执行需要耗费两秒,最后的结果实际是每隔两秒执行一次

4.定时每隔固定的延迟时间执行scheduleWithFixedDelay

  • //delay  正在的延迟执行
    private static void withFixedDelay() {
          
          
        scheduledExecutorService = Executors.newScheduledThreadPool(2);
        scheduledExecutorService.scheduleWithFixedDelay(()->{
          
          
            log.debug("start---task1");
            try {
          
          
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
          
          
                e.printStackTrace();
            }
        },2,1,TimeUnit.SECONDS);
    }
    
  • 此处实际是每隔三秒执行一次,因为任务执行需要花费2秒,然后又延迟了1秒,所以是每隔3秒执行一次

5.每周的周三 22点0分0秒去执行一个任务 同步redis mysql 只有一个线程

  • package BingFaBianCheng.bingFaBianCheng16.shadow.threadPool;
    
    import lombok.extern.slf4j.Slf4j;
    
    import java.time.DayOfWeek;
    import java.time.Duration;
    import java.time.LocalDateTime;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ScheduledThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @Author 钢牌讲师--子路
     * 每周的周三 22点0分0秒去执行一个任务 同步redis mysql 只有一个线程
     **/
    @Slf4j(topic = "e")
    public class TestThreadExecutorPool10 {
          
          
    
    
        public static void main(String[] args) throws InterruptedException, ExecutionException {
          
          
            //一个线程
            ScheduledThreadPoolExecutor scheduled
                    = new ScheduledThreadPoolExecutor(1);
    
            /**
             * 1、当前在编码的时候距离周三还有多久------initialDelay
             *     当前时间   周三的时间
             * 2、下一次多久之后执行(周期时间)delay
             * 3、单位
             */
            //LocalDateTime---java8的新时间工具类
            //当前时间
            LocalDateTime currentTime = LocalDateTime.now();
            //周三的时间
            // 22点0分0秒
            // DayOfWeek.WEDNESDAY--星期三
            LocalDateTime targetTime = currentTime.withHour(22).withMinute(0).withSecond(0).withNano(0).with(DayOfWeek.WEDNESDAY);
    
            // 当前时间在周三之后,则获取下周三
            if(targetTime.compareTo(currentTime)<0){
          
          
                targetTime = targetTime.plusWeeks(1);
    
            }
    
            // 获取时间差,转换成秒
            long l = Duration.between(currentTime, targetTime).toMillis();
            long delay = 1000 * 60 *60 *24 *7;
            log.debug("当前时间:[{}]",l);
            log.debug("目标时间:[{}]",targetTime);
    
            scheduled.scheduleWithFixedDelay(()->{
          
          
                log.debug("redis---mysql async");
            },l,delay,TimeUnit.MILLISECONDS);
    
    
    
    
        }
    
    
        static class MyTask implements Runnable {
          
          
            private int taskNum;
    
            public int getTaskNum() {
          
          
                return taskNum;
            }
    
            public MyTask(int num) {
          
          
                this.taskNum = num;
            }
    
            @Override
            public void run() {
          
          
                log.debug(getTaskNum()+"");
            }
        }
    }
    
    

猜你喜欢

转载自blog.csdn.net/Markland_l/article/details/112135207