Java 线程池

本文深入介绍了Java中的线程池概念及其优势,包括如何创建和使用线程池,展示了ExecutorService、ThreadPoolExecutor等核心API,并探讨了线程池的参数配置如核心线程数、最大线程数等。此外,还详细讲解了任务提交、任务拒绝策略、任务取消及线程池监控等方面,最后给出了不同场景下线程池的关闭方法及其区别。

线程池

1. 简介

线程池Thread Pool,是一个容纳多个线程的容器,里面的线程可以反复使用。

好处:

  • 降低资源消耗:通过重复利用已创建的线程,降低线程创建和销毁造成的资源消耗。
  • 提高响应速度:当有任务时,无需等待线程创建,就能立即执行。
  • 提高线程的可管理性:线程池可以对线程进行统一的分配、调优和监控。

应用场景:Tomcat服务器、数据库连接池等。

代码:

javase/src/code16/test10/Task.java:

package code16.test10;

public class Task implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

javase/src/code16/test10/Test01.java:

package code16.test10;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test01 {
    public static void main(String[] args) {
        /*
         * 创建任务
         */
        Task task1 = new Task();
        Task task2 = new Task();
        Task task3 = new Task();

        /*
         * 创建线程
         */
        // Thread thread = new Thread(mr1, mr2, mr3); // 没有该写法,一个线程只能执行一个任务
        // Thread thread1 = new Thread(mr1);
        // Thread thread2 = new Thread(mr2);
        // Thread thread3 = new Thread(mr3);
        // // 线程不能复用,损耗资源

        // 创建只有一个线程的线程池
        ExecutorService threadPool = Executors.newSingleThreadExecutor();

        // /*
        //  * 启动线程
        //  */
        // thread.start();
        // thread1.start();
        // thread2.start();
        // thread3.start();

        /*
         * 提交任务
         */
        threadPool.execute(task1);
        threadPool.execute(task2);
        threadPool.execute(task3);
        // 线程得到复用,降低资源损耗

        // 关闭线程池
        threadPool.shutdown();
    }
}

java执行结果:

在这里插入图片描述

2. 线程池的API

线程池相关的API都在java.util.concurrent包中。

|- Executor
    |- ExecutorService
        |- AbstractExecutorService
            |- ThreadPoolExecutor // 核心线程池
                |- ScheduledThreadPoolExecutor
        |- ScheduledExecutorService // 调度线程池
            |- ScheduledThreadPoolExecutor

3. 创建线程池

线程池的基本属性:

属性含义描述
corePoolSize核心线程数核心线程:只要线程池不关闭,就不会被销毁的线程
maximumPoolSize最大线程数线程池中最多允许有的线程数
keepAliveTime空闲线程存活时间非核心线程(线程池中除了核心线程以外的线程)没有执行任务时,超过空闲线程存活时间,就会被清理
unit时间单位keepAliveTime的时间单位
workQueue任务队列存放任务(Runnable实例)的容器,提交给线程池的任务都位于这里,线程池中的线程也都是在该容器中领取任务。常用的有LinkedBlockingQueue、ArrayBlockingQueue等
threadFactory线程工厂指定线程的创建过程
handler任务拒绝策略指定线程池拒绝提交的任务后,执行的操作

核心线程池:ThreadPoolExecutor。

其它线程池:

  • FixedThreadPool:固定线程数量的线程池。
  • SingleThreadExecutor:只有一个线程的线程池。
  • CachedThreadPool:可缓存的线程池。

这三种线程池都是由Executors(线程池的工具类),对ThreadPoolExecutor进行包装,从而创建的。

注:实际应用中,一般不使用这三种线程池,存在风险。

代码:

javase/src/code16/test10/Test02.java:

package code16.test10;

import java.util.concurrent.*;

public class Test02 {
    public static void main(String[] args) {
        // 创建任务
        Task task1 = new Task();
        Task task2 = new Task();
        Task task3 = new Task();

        /*
         * 创建线程池
         */
        // 1. ThreadPoolExecutor
        // ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
        //         10, // 核心线程数
        //         25, // 最大线程数
        //         10, // 空闲线程存活时间
        //         TimeUnit.SECONDS, // keepAliveTime的单位,这里为秒
        //         new LinkedBlockingQueue<>(), // 任务队列
        //         new CustomThreadFactory(), // 线程工厂
        //         // Executors.defaultThreadFactory() // 默认使用的线程工厂
        //         // new ThreadPoolExecutor.AbortPolicy() // 默认使用的任务拒绝策略,这里为直接抛出RejectedExecutionException
        // );

        // 2. FixedThreadPool
        // ExecutorService fixedThreadPool = new ThreadPoolExecutor(
        //         10, 10, // 核心线程数和最大线程数相同,即线程池中的线程都是核心线程。由于核心线程在线程池关闭之前不会被销毁,因此线程数量固定
        //         0L, TimeUnit.MILLISECONDS, // 空闲线程存活时间为0ms
        //         new LinkedBlockingQueue<>() // 任务队列使用的是LinkedBlockingQueue,该队列的容量为Integer.MAX_VALUE,堆积大量请求时,会导致资源耗尽,从而报错OOM(OutOfMemoryError)
        // );
        // ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);

        // 3. SingleThreadExecutor
        // ExecutorService singleThreadPool = new Executors.FinalizableDelegatedExecutorService(
        //         new ThreadPoolExecutor(
        //                 1, 1, // 核心线程数和最大线程数都为1
        //                 0L, TimeUnit.MILLISECONDS, // 空闲线程存活时间为0ms
        //                 new LinkedBlockingQueue<>()
        //         )
        // );
        // ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();

        // 4. CachedThreadPool
        // ExecutorService CachedThreadPool =new ThreadPoolExecutor(
        //         0, Integer.MAX_VALUE, // 核心线程数为0,最大线程数为Integer.MAX_VALUE(创建大量线程时会导致OOM),即线程池中都是非核心线程。由于非核心线程在没有执行任务时,超过空闲线程存活时间就会被清理,因此是可缓存的
        //         60L, TimeUnit.SECONDS, // 空闲线程存活时间为60s
        //         new SynchronousQueue<>() // 任务队列使用的是SynchronousQueue,该队列是一个同步队列
        // );
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

        // 提交任务
        cachedThreadPool.execute(task1);
        cachedThreadPool.execute(task2);
        cachedThreadPool.execute(task3);

        // 关闭线程池
        cachedThreadPool.shutdown();
    }
}

/*
 * 线程工厂
 */
class CustomThreadFactory implements ThreadFactory {

    private static int count = 1;

    /*
     * 定义线程的创建过程
     */
    @Override
    public Thread newThread(Runnable r) { // r代表新线程要执行的任务
        Thread thread = new Thread(r);
        thread.setName("线程" + count++ + "号");
        return thread;
    }
}

java执行结果:

自行测试。

4. 任务

4.1. 简介

任务的类型有两种:

  • Runnable:实现了Runnable接口的类,在重写的run方法中定义任务内容,run方法无返回值。
  • Callable:实现了Callable接口的类,在重写的call方法中定义任务内容,call方法有返回值。

4.2. 提交任务

向线程池提交任务,由线程池中的线程来执行这些任务。

提交任务的两种方法:

  • execute

    • 提交一个Runnable类型的任务(实现了Runnable接口的类)。
    • 返回值类型为void,无任务执行结果。
    • 当任务被拒绝时,抛出RejectedExecutionException异常。
  • submit

    • 提交一个Callable类型(实现了Callable接口的类)或Runnable类型的任务。
    • 返回值类型为Future,封装了任务执行结果。

实际开发中一般都使用submit提交任务。

代码:

javase/src/code16/test10/Test03.java:

package code16.test10;

import java.util.concurrent.*;

public class Test03 {
    public static void main(String[] args) {
        // test01();
        test02();
    }

    /*
     * 提交任务,获取任务执行结果
     */
    public static void test01() {
        RunnableTask runnableTask = new RunnableTask();
        CallableTask callableTask = new CallableTask();

        ExecutorService threadPool = Executors.newSingleThreadExecutor();

        /*
         * 提交任务
         */
        // 1. execute
        // threadPool.execute(runnableTask);
        // threadPool.shutdown();

        // 2. submit
        // 提交Runnable任务
        // Future<?> future = threadPool.submit(runnableTask); // 泛型是任务执行结果的类型
        // 提交Runnable任务并指定执行结果
        // Future<String> future = threadPool.submit(runnableTask, "任务完成");
        // 提交Callable任务
        Future<Integer> future = threadPool.submit(callableTask);

        /*
         * 获取任务执行结果
         * 通过Future对象的get方法,获取任务执行结果
         * 该方法是一个阻塞方法,即执行任务、获取任务执行结果的线程,会一直等到任务执行完毕,才会继续往下执行
         */
        try {
            // Object result = future.get(); // null
            // String result = future.get(); // 任务完成
            // Integer result = future.get(); // 2
            Integer result = future.get(3, TimeUnit.SECONDS); // 设置获取任务执行结果的超时时间,超过该时间后,线程就不再继续等待,直接抛出TimeoutException异常
            System.out.println(result);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }

    /*
     * 按任务执行完成的先后顺序,获取任务执行结果
     */
    public static void test02() {
        ExecutorService threadPool = Executors.newFixedThreadPool(5);

        /*
         * CompletionService
         * 提交任务、返回任务执行结果
         * 先执行完的任务,先返回执行结果
         */
        CompletionService<Integer> completionService = new ExecutorCompletionService<>(threadPool);

        for (int i = 5; i >= 1; i--) {
            int timeout = i; // 执行时间
            completionService.submit(() -> {
                System.out.println("执行顺序:" + timeout);
                Thread.sleep(timeout * 100L);
                return timeout;
            });
        }

        for (int i = 5; i >= 1; i--) {
            Future<Integer> future;
            try {
                future = completionService.take();
                System.out.println("返回顺序:" + future.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            } finally {
                threadPool.shutdown();
            }
        }
    }
}

/*
 * Runnable任务
 */
class RunnableTask implements Runnable {

    // 定义任务内容
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

/*
 * Callable任务
 */
class CallableTask implements Callable<Integer> { // 泛型是任务执行结果的类型

    @Override
    public Integer call() throws Exception {
        Thread.sleep(5000); // 模拟任务执行时间长的情况
        return 1 + 1;
    }
}

java执行结果:

自行测试。

4.3. 取消任务

通过Future对象的cancel方法取消任务。

任务状态:

  • 任务未执行:submit—>进入任务队列(入队)。
  • 任务正在执行:出队—>任务完成。
  • 任务完成。

cancel只能取消正在执行的任务。

代码:

javase/src/code16/test10/Test04.java:

package code16.test10;

import java.util.concurrent.*;

public class Test04 {
    public static void main(String[] args) {
        CallableTask2 callableTask = new CallableTask2();
        ExecutorService threadPool = Executors.newSingleThreadExecutor();

        /*
         * 让第二个任务处于未执行的状态
         *
         * 可以这样模拟的原因:
         * 提交了多次任务,而一个线程一次只能执行一个任务,如果没有空闲线程,后面的任务会在任务队列中等待,从而处于未执行的状态
         */
        // Future<Integer> future1 = threadPool.submit(callableTask);
        Future<Integer> future2 = threadPool.submit(callableTask);

        /*
         * 让第二个任务处于已执行完成或正在执行的状态
         */
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("任务是否完成:" + future2.isDone());

        /*
         * 取消任务
         * true表示调用正在执行任务的线程的interrupt方法,并由开发者通过Thread.interrupted()方法,中断正在执行的任务;false表示任务依然会执行完(只是无法通过Future对象的get方法获取任务执行结果)
         * 无论传入true还是false,都不一定能取消成功
         * 取消成功返回true,失败返回false
         */
        boolean cancel = future2.cancel(true); // 只会影响正在执行的任务,而不会影响未执行和已完成的任务
        System.out.println("任务是否取消成功:" + cancel);
        // System.out.println("任务是否取消成功:" + future2.isCancelled());
        try {
            System.out.println(future2.get()); // 取消任务后,获取任务结果会抛出异常CancellationException
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

class CallableTask2 implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        /*
         * 模拟任务正在执行
         */
        int count = 0;
        while (!Thread.interrupted()) { // 线程被中断时退出循环
            count++;
        }
        System.out.println(count);

        return 1 + 1;
    }
}

java执行结果:

自行测试。

4.4. 任务拒绝策略

任务被拒绝的时机:

  • 线程池关闭。
  • 线程池无空闲线程,且任务队列已满。

任务拒绝策略:指定线程池拒绝提交的任务后,执行的操作。

任务拒绝策略描述
AborPolicy默认策略(最常用),抛出RejectedException异常
DiscardPolicy直接丢弃任务
CallerRunsPolicy使用调用者线程再执行被拒绝的任务
DiscardOldestPolicy丢弃处于任务队列头部的任务,并在队尾添加被拒绝的任务

代码:

javase/src/code16/test10/Test05.java:

package code16.test10;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Test05 {
    public static void main(String[] args) {
        /*
         * 创造任务被拒绝的时机
         */
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                1, 1,
                0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1),
                // new ThreadPoolExecutor.AbortPolicy() // 默认策略(最常用),抛出RejectedException异常
                // new ThreadPoolExecutor.DiscardPolicy() // 直接丢弃任务
                // new ThreadPoolExecutor.CallerRunsPolicy() // 使用调用者线程再执行被拒绝的任务
                new ThreadPoolExecutor.DiscardOldestPolicy() // 丢弃处于任务队列头部的任务,并在队尾添加被拒绝的任务
        );
        try {
            threadPool.execute(new RunnableTask2(1));
            threadPool.execute(new RunnableTask2(2));
            // 线程池无空闲线程,且任务队列已满
            threadPool.execute(new RunnableTask2(3));
        } catch (RejectedExecutionException e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

class RunnableTask2 implements Runnable {

    private int index; // 任务编号

    public RunnableTask2() {
    }

    public RunnableTask2(int index) {
        this.index = index;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + ":" + index);
    }
}

java执行结果:

自行测试。

4.5. 执行特殊任务

代码:

javase/src/code16/test10/Test06.java:

package code16.test10;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class Test06 {
    public static void main(String[] args) {
        // test01();
        // test02();
        test03();
    }

    /*
     * 执行批量任务
     */
    public static void test01() {
        List<CallableTask3> tasks = new ArrayList<>();
        for (int i = 1; i < 10; i++) {
            tasks.add(new CallableTask3(i));
        }

        ExecutorService threadPool = Executors.newFixedThreadPool(5);

        try {
            /*
             * invokeAll 执行批量任务
             * 传入Callable类型的任务集合,按集合中元素的顺序执行任务,并按此顺序返回Future任务执行结果的集合
             */
            // List<Future<Integer>> futures = threadPool.invokeAll(tasks);
            // List<Future<Integer>> futures = threadPool.invokeAll(tasks, 1, TimeUnit.SECONDS); // 超时时间为1秒,超时后,未执行完的任务将被取消
            // for (Future<Integer> future : futures) {
            //     System.out.println(future.get());
            // }

            /*
             * invokeAny 执行批量任务
             * 传入Callable类型的任务集合,返回最先完成的任务的执行结果,取消其它未完成的任务
             */
            Integer result = threadPool.invokeAny(tasks);
            System.out.println(result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }

    /*
     * 执行定时任务
     */
    public static void test02() {
        /*
         * 调度线程池:可以执行定时任务和周期性任务的线程池
         */
        // ScheduledExecutorService scheduledThreadPool = new ScheduledThreadPoolExecutor(5);
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); // 指定核心线程数为5

        System.out.println(LocalDateTime.now());

        /*
         * 提交延时任务,即线程领取到任务后,多久才开始执行
         * 延时任务默认只执行一次
         */
        // scheduledThreadPool.schedule(new RunnableTask3(), 3, TimeUnit.SECONDS);
        ScheduledFuture<String> future = scheduledThreadPool.schedule(new CallableTask4(), 3, TimeUnit.SECONDS);
        try {
            System.out.println(future.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            scheduledThreadPool.shutdown();
        }

        // scheduledThreadPool.shutdown();
    }

    /*
     * 执行周期性任务
     */
    public static void test03() {
        RunnableTask4 task = new RunnableTask4();

        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);

        System.out.println(LocalDateTime.now());

        /*
         * scheduleAtFixedRate 按固定时间执行周期性任务
         * 固定时间:每次执行任务的时间相同,即每过相同的时间,无论前一个任务是否执行完成,都会执行下一个任务
         */
        // ScheduledFuture<?> future = scheduledThreadPool.scheduleAtFixedRate(task, 1, 1, TimeUnit.SECONDS);// 参数从左至右分别代表:任务、延时时间、固定时间、时间单位

        /*
         * scheduleWithFixedDelay 按间隔时间执行周期性任务
         * 间隔时间:每次执行任务的时间间隔相同,即等到前一个任务执行完,再过一定的时间间隔,才执行下一个任务
         */
        ScheduledFuture<?> future = scheduledThreadPool.scheduleWithFixedDelay(task, 1, 1, TimeUnit.SECONDS);

        try {
            // 使当前线程休眠5S
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        future.cancel(false);

        scheduledThreadPool.shutdown();
    }
}

class CallableTask3 implements Callable<Integer> {

    private int index; // 任务编号

    public CallableTask3() {
    }

    public CallableTask3(int index) {
        this.index = index;
    }

    @Override
    public Integer call() throws Exception {
        Thread.sleep(1000);

        return index;
    }
}

class RunnableTask3 implements Runnable {

    @Override
    public void run() {
        System.out.println(LocalDateTime.now());
    }
}

class CallableTask4 implements Callable<String> {

    @Override
    public String call() throws Exception {
        return LocalDateTime.now().toString();
    }
}

class RunnableTask4 implements Runnable {

    @Override
    public void run() {
        System.out.println(LocalDateTime.now());
        try {
            Thread.sleep(1000); // 模拟任务执行时长
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

java执行结果:

自行测试。

5. 关闭线程池

5.1. 简介

通过线程池的shutdownshutdownNow方法,关闭线程池。

关闭线程池后:

  • shutdown(常用):

    • 不再接收新任务,并拒绝后面的任务。

    • 继续执行完任务队列中的任务。

  • shutdownNow(一般不用):

    • 不再接收新任务,并拒绝后面的任务。
    • 中断所有正在执行的任务(通过interrupt和interrupted方法),并返回任务队列中的任务。

5.2. 应用

代码:

javase/src/code16/test10/Test07.java:

package code16.test10;

import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Test07 {
    public static void main(String[] args) {
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                1, 1,
                0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(1)
        );
        try {
            threadPool.execute(new RunnableTask5(1));
            threadPool.execute(new RunnableTask5(2));
        } catch (RejectedExecutionException e) {
            e.printStackTrace();
        } finally {
            // threadPool.shutdown(); // 继续执行完任务队列中的任务
            List<Runnable> tasks = threadPool.shutdownNow(); // 尝试中断所有正在执行的任务(通过interrupt和interrupted方法),并返回任务队列中的所有任务
            for (Runnable task : tasks) {
                task.run();
            }

            // 关闭线程池后再提交任务
            threadPool.execute(new RunnableTask5(3)); // 不再接收新任务,并拒绝后面的任务
        }
    }
}

class RunnableTask5 implements Runnable {

    private int index; // 任务编号

    public RunnableTask5() {
    }

    public RunnableTask5(int index) {
        this.index = index;
    }

    @Override
    public void run() {
        if (Thread.interrupted()) {
            System.out.println(Thread.currentThread().getName() + "被中断");
            return;
        }

        System.out.println(Thread.currentThread().getName() + ":" + index);
    }
}

java执行结果:

自行测试。

5.3. shutdown与shutdownNow的区别

shutdownshutdownNow
立即关闭线程池不是
不再接收新任务
继续执行完任务队列中的任务不是
返回任务队列中的任务不是
线程池状态(后面会讲)SHUTDOWNSTOP

6. 线程池的生命周期

在这里插入图片描述

  • RUNNING:线程池正在运行。可以接收新任务,并且也能处理任务队列中的任务
  • SHUTDOWN:线程池准备关闭。不接受新任务,但可以处理任务队列中的任务。
  • STOP:线程池准备关闭。不接受新任务,也不处理任务队列中的任务,正在执行的任务也被中断。
  • TIDYNG:线程池正在关闭。所有任务已终止,线程池中的线程数量为0。
  • TERMINATED:线程池彻底关闭。

7. 监控线程池

ThreadPoolExecutor提供了监控线程池的方法:

方法返回值
getActiveCount()正在工作的线程数
getPoolSize()当前存在的线程数
getLargestPoolSize()历史最大的线程数
getTaskCount()已提交的任务数
getCompletedTaskCount()已完成的任务数
getQueue()任务队列

代码:

javase/src/code16/test10/MonitorThreadPool.java:

package code16.test10;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MonitorThreadPool extends ThreadPoolExecutor {

    public MonitorThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    /*
     * 在每个任务执行之前,要进行的操作
     */
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        monitor();
    }

    /*
     * 在每个任务执行完成之后,要进行的操作
     */
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        monitor();
    }

    /*
     * 在线程池关闭前,要进行的操作
     */
    @Override
    protected void terminated() {
        monitor();
    }

    /*
     * 监控线程池情况
     */
    public void monitor() {
        System.out.print("正在工作的线程数:" + getActiveCount() + "\t");
        System.out.print("当前存在的线程数:" + getPoolSize() + "\t");
        System.out.print("历史存在的最大线程数:" + getLargestPoolSize() + "\t");
        System.out.print("已提交的任务数:" + getTaskCount() + "\t");
        System.out.print("已完成的任务数:" + getCompletedTaskCount() + "\t");
        System.out.println("队列中的任务数:" + getQueue().size());
    }
}

javase/src/code16/test10/Test08.java:

package code16.test10;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class Test08 {
    public static void main(String[] args) {
        MonitorThreadPool threadPool = new MonitorThreadPool(1, 3, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2));

        try {
            for (int i = 5; i > 0; i--) {
                threadPool.submit(new RunnableTask6(i));
                Thread.sleep(500);
            }

            // 使主线程休眠6秒钟,在关闭线程池之前获取一次线程池情况
            Thread.sleep(6000);
            threadPool.monitor();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

class RunnableTask6 implements Runnable {

    private int timeout;

    public RunnableTask6(int timeout) {
        this.timeout = timeout;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(timeout * 1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

java执行结果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

睡醒的人想拯救世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值