java线程池

线程池核心参数

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

corePoolSzie

:线程池核心线程数。核心线程即使空闲也不会被销毁。(比如最大线程数为10,核心线程数为8,就算这8个线程空闲,也不会被销毁,但是如果第9个线程空闲,那么第9个线程会被销毁。)

maximumPoolSize

:线程池最大线程数。

keepAliveTime

:非核心线程空闲的最大存活时间(同上,第9个线程是非核心线程,空闲时间超过了keepAliveTime就会被销毁)

unit

:时间单位

workQueue

:阻塞队列,存在多种实现,按需选择

handler

:拒绝策略处理器,maximumPoolSize和workQueue被填满时,放不下新线程就会使用拒绝策略。

拒绝策略

AbortPolicy

:直接抛出一个任务被线程池拒绝的异常。

public class newThreadPoolExecutor {
    public static void main(String[] args) {
        // 创建线程池,最大线程数为10,核心线程数为8,线程空闲存活时间为100ms
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                8,                // 核心线程数
                10,               // 最大线程数
                100,              // 非核心线程存活时间
                TimeUnit.MILLISECONDS,   // 时间单位为毫秒
                new LinkedBlockingQueue<>(10),  // 阻塞队列,最大容量为10
                new ThreadPoolExecutor.AbortPolicy()  // 拒绝策略:直接抛出异常
        );
        // 提交20个任务,超过最大线程数和队列容量将触发拒绝策略
        int count = 0;
        for (int i = 0; i < 30; i++) {
            count++;
            final int finalCount = count;
            try {
                // 提交任务
                threadPoolExecutor.submit(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("这是线程 " + finalCount);
                        try {
                            Thread.sleep(1000);  // 模拟任务执行1秒钟
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                });
            } catch (RejectedExecutionException e) {
                e.printStackTrace();
                System.out.println("任务 " + finalCount + " 被拒绝执行!");
            }
        }
​
        // 关闭线程池
        threadPoolExecutor.shutdown();
    }
}
​
这是线程 1
这是线程 7
这是线程 5
这是线程 4
这是线程 3
这是线程 2
这是线程 6
这是线程 8
这是线程 19
这是线程 20
任务 21 被拒绝执行!
任务 22 被拒绝执行!
任务 23 被拒绝执行!
任务 24 被拒绝执行!
任务 25 被拒绝执行!
任务 26 被拒绝执行!
任务 27 被拒绝执行!
任务 28 被拒绝执行!
任务 29 被拒绝执行!
任务 30 被拒绝执行!
java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@6e0be858 rejected from java.util.concurrent.ThreadPoolExecutor@61bbe9ba[Running, pool size = 10, active threads = 10, queued tasks = 10, completed tasks = 0]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
    at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
    at ThreadPool.newThreadPoolExecutor.main(newThreadPoolExecutor.java:27)

DiscardPolicy

:静默拒绝(冷暴力),什么也不返回

这是线程 3
这是线程 1
这是线程 5
这是线程 4
这是线程 2
这是线程 8
这是线程 7
这是线程 6
这是线程 20
这是线程 19
这是线程 9
这是线程 12
这是线程 10
这是线程 14
这是线程 13
这是线程 11
这是线程 15
这是线程 17
这是线程 18
这是线程 16

CallerRunsPolicy

:当一个任务被提交到线程池时,如果线程池的线程数已经达到最大线程数,且任务队列也已经满了,那么 CallerRunsPolicy 并不会直接拒绝任务(即不抛出异常),而是将该任务交由 提交任务的线程 执行,也就是说,任务会在提交它的线程中运行,而不是由线程池的线程来处理。

更换输出的语句

 System.out.println("这是线程 " +Thread.currentThread().getName() + ",正在执行任务" + finalCount);
这是线程 pool-1-thread-1,正在执行任务1
这是线程 pool-1-thread-5,正在执行任务5
这是线程 pool-1-thread-6,正在执行任务6
这是线程 pool-1-thread-3,正在执行任务3
这是线程 pool-1-thread-4,正在执行任务4
这是线程 pool-1-thread-8,正在执行任务8
这是线程 pool-1-thread-2,正在执行任务2
这是线程 pool-1-thread-9,正在执行任务19
这是线程 pool-1-thread-7,正在执行任务7
这是线程 main,正在执行任务21
这是线程 pool-1-thread-10,正在执行任务20
这是线程 pool-1-thread-6,正在执行任务9
这是线程 pool-1-thread-2,正在执行任务12
这是线程 pool-1-thread-1,正在执行任务10
这是线程 pool-1-thread-10,正在执行任务15
这是线程 pool-1-thread-8,正在执行任务11
这是线程 main,正在执行任务22
这是线程 pool-1-thread-3,正在执行任务16
这是线程 pool-1-thread-9,正在执行任务18
这是线程 pool-1-thread-4,正在执行任务14
这是线程 pool-1-thread-5,正在执行任务17
这是线程 pool-1-thread-7,正在执行任务13
这是线程 pool-1-thread-4,正在执行任务23
这是线程 pool-1-thread-1,正在执行任务25
这是线程 pool-1-thread-9,正在执行任务24
这是线程 pool-1-thread-5,正在执行任务26
这是线程 pool-1-thread-10,正在执行任务27
这是线程 pool-1-thread-2,正在执行任务29
这是线程 pool-1-thread-6,正在执行任务28
这是线程 pool-1-thread-8,正在执行任务30

有的被main线程执行。

DiscardOldestPolicy

当线程池队列满了并且不能再分配任务时,DiscardOldestPolicy 会丢弃队列中最旧的任务,尝试为新的任务腾出空间。这意味着,队列中最旧的任务(如果当前任务队列已满且线程池无法再处理新任务)会被丢弃,而新的任务会被加入到线程池中执行。

这是线程 pool-1-thread-2,正在执行任务 2
这是线程 pool-1-thread-5,正在执行任务 5
这是线程 pool-1-thread-4,正在执行任务 4
这是线程 pool-1-thread-3,正在执行任务 3
这是线程 pool-1-thread-8,正在执行任务 8
这是线程 pool-1-thread-1,正在执行任务 1
这是线程 pool-1-thread-7,正在执行任务 7
这是线程 pool-1-thread-6,正在执行任务 6
这是线程 pool-1-thread-9,正在执行任务 19
这是线程 pool-1-thread-10,正在执行任务 20
这是线程 pool-1-thread-5,正在执行任务 21
这是线程 pool-1-thread-3,正在执行任务 28
这是线程 pool-1-thread-6,正在执行任务 27
这是线程 pool-1-thread-7,正在执行任务 25
这是线程 pool-1-thread-10,正在执行任务 23
这是线程 pool-1-thread-8,正在执行任务 24
这是线程 pool-1-thread-9,正在执行任务 22
这是线程 pool-1-thread-4,正在执行任务 26
这是线程 pool-1-thread-1,正在执行任务 30
这是线程 pool-1-thread-2,正在执行任务 29

阻塞队列

ArrayBlockingQueue

:适用于固定大小、任务量已知的场景。

特点:基于数组的有界阻塞队列。

实现机制:固定大小,必须在创建时指定容量。

适用场景

  • 任务量是已知的且有界的场景。

  • 希望控制队列大小以限制内存占用。

注意

  • 若队列已满,put 操作会阻塞;若队列为空,take 操作会阻塞。

        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 0,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(5));

LinkedBlockingQueue

:适用于任务数量不固定、队列可能增长的场景。

特点:基于链表的阻塞队列,容量可指定(默认无界,实际为 Integer.MAX_VALUE)。

实现机制

  • 无界模式下,队列大小仅受内存限制。

  • 有界模式下,防止过多任务积压。

适用场景

  • 任务数量不确定,需动态调整队列大小的场景。

  • 默认的 Executors.newFixedThreadPool() 就使用了此队列。

注意

  • 无界队列可能导致内存耗尽。

        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 0,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>());

PriorityBlockingQueue

:适用于优先级任务调度的场景。

特点:基于优先级排序的无界阻塞队列。

实现机制

  • 内部使用堆结构实现,元素按自然顺序或自定义比较器排序。

  • 队列无容量限制,但需要合理控制元素数量。

适用场景

  • 需要根据优先级处理任务的场景(如调度系统)。

注意

  • 无法保证元素的 FIFO 顺序,仅按照优先级出队。

元素需实现comparable接口。否则就报错。

public class test {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0,
                TimeUnit.SECONDS, new PriorityBlockingQueue<>());
        for (int i = 0; i < 8; i++) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                        System.out.println("hello");
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
        }
    }
}
​
Exception in thread "main" java.lang.ClassCastException: ThreadPool.test$1 cannot be cast to java.lang.Comparable
    at java.util.concurrent.PriorityBlockingQueue.siftUpComparable(PriorityBlockingQueue.java:357)
    at java.util.concurrent.PriorityBlockingQueue.offer(PriorityBlockingQueue.java:489)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1371)
    at ThreadPool.test.main(test.java:10)

实现接口

// 包装任务类
class PriorityRunnable implements Runnable,Comparable<PriorityTask>{
    final int priority;
    private final Runnable task;
​
    public PriorityRunnable(int priority, Runnable task) {
        this.priority = priority;
        this.task = task;
    }
​
     @Override
    public int compareTo(PriorityTask other) {
        return Integer.compare(other.priority, this.priority); // 优先级高的先执行
    }
}

DelayQueue

:适用于延时任务和定时任务的场景。

特点:支持延迟的无界阻塞队列。

实现机制

  • 元素需实现 Delayed 接口,规定延迟时间。

  • 只有延迟时间到期的元素才能被取出。

适用场景

  • 延迟任务或定时任务的调度(如定时消息推送)。

注意

  • 延迟到期的任务出队可能略有延迟(时间粒度)。

SynchronousQueue:适用于直接交换任务的场景。

LinkedTransferQueue:适用于需要高效任务传输的场景。

BlockingDeque:适用于需要双端队列操作的场景。

线程池种类

FixedThreadPool

线程池中线程的数量是固定的。

如果所有线程都在工作,新任务会进入阻塞队列等待。

使用无界的 LinkedBlockingQueue 存储任务,防止线程池因任务过多而耗尽资源。阻塞队列可存Integer.MAX_VALUE,所以任务不会被拒绝,所以不指定决绝策略。

核心线程数跟最大线程数一致。

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(nThreads);

SingleThreadExecutor

  • 线程池中只有一个线程,所有任务按照提交顺序串行执行。

  • 如果线程意外终止,会创建一个新的线程继续执行任务。

  • 使用无界的 LinkedBlockingQueue

核心线程和最大线程都是1,

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

适用场景

  • 适用于需要顺序执行任务的场景,如日志记录、任务调度。

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

实际实现: 内部是 ThreadPoolExecutor,核心线程数和最大线程数均为 1。

CachedThreadPool

特点

  • 没有核心线程数 (corePoolSize = 0),最大线程数为 Integer.MAX_VALUE

  • 空闲线程存活时间为 60 秒,超过存活时间未被使用的线程将被回收。

  • 使用 SynchronousQueue,每个任务直接交给空闲线程,如果没有空闲线程则创建新线程。

核心线程0,

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

适用场景

  • 适合大量短期异步任务的场景,能够快速提供线程资源。

  • 不适合长期占用线程的任务,可能导致线程数量过多。

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

ScheduledThreadPool

有参构造为这样,可以指定核心线程数量,最大线程数量默认Integer.MAX_VALUE,存活时间0,延时队列。

    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

特点

  • 专门用于执行定时任务或周期性任务。

  • 核心线程数固定,非核心线程数无限制,且非核心线程空闲后立即回收。

  • 使用 DelayedWorkQueue 存储任务。

适用场景

  • 适用于定时执行任务的场景,例如定时备份、轮询服务。

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(corePoolSize);

实际实现: 使用 ScheduledThreadPoolExecutor 类,扩展自 ThreadPoolExecutor

SingleThreadScheduledExecutor

特点

  • 类似于单线程线程池,但专门用于执行定时任务。

  • 保证任务按提交顺序串行执行,适用于需要顺序执行的定时任务。

内部只有一个线程。

    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }

适用场景

  • 适用于需要单一线程按顺序执行定时任务的场景。

ScheduledExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();

应该手动 new ThreadPoolExecutor 来创建线程池。

可能因为资源耗尽导致 OOM 问题。

线程池提交的任务可以被撤回吗?

可以调用生成的future对象的cancel方法撤回。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值