学习 Java 线程池

一、线程池创建

承接深入剖析Java创建线程的方式(学习向)-优快云博客,创建线程池有两种方式:

1. 调用Executors类的静态方法

java.util.concurrent包下的Executors类,有很多静态方法,例如newFixedThreadPool(), newWorkStealingPool(), newSingleThreadExecutor()等来创建线程池,但看源码,其实还是调用ThreadPoolExecutor,只是用写好的参数构造罢了。这种方法由于传参不当,可能导致OOM,因此很少用

2. 手动创建ThreadPoolExecutor实例

同样java.util.concurrent包下的ThreadPoolExecutor,才是我们熟知的线程池类,我们可以自定义参数来解决OOM的问题

二、线程池参数+工作原理

参数:

corePoolSize核心线程数 默认不会销毁,从而达到线程复用
maximumPoolSize最大线程数 核心线程都在占用时,对新任务启动临时线程。临时线程最大数量+核心线程数=最大线程数
keepAliveTime临时线程的最大存活时间 临时线程在无任务的keepAliveTime时间后会自动销毁
unit存活时间的单位keepAliveTime的单位
threadFactory创建线程使用的工厂创建线程使用的工厂
workQueue任务等待队列最大线程数后仍然有新任务,则任务加入等待队列
handler拒绝策略等待队列满了会拒绝新任务(有不同拒绝策略)

工作原理:

        1. 创建线程池

        2. 新任务加入,创建核心线程(也可以用prestartCoreThread()提前创建)

        3. 新任务加入,若有空闲核心线程则复用,无则创建

        4. 重复3……直到核心线程都创建完,且都在被占用

        5. 新任务加入,创建临时线程来处理任务(处理完且空闲时间超过keepAliveTime则销毁)

        6. 重复5……直到临时线程也创建满了(核心+临时线程数达到最大线程数)

        7. 新任务加入,进入等待队列

        8. 重复7……等待队列也满了

        9. 还有新任务加入,采用拒绝策略

三、拒绝策略有哪些

1. 抛异常 (RejectedExecutionException)

2. 丢弃队列最前边的任务(DiscardOldestPolicy)

3. 丢弃这个新任务(DiscardPolicy)

4. 调用线程池的线程自己运行该任务(CallerRunsPolicy)

四、如何使用线程池

先创建线程池:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心线程数
                2, // 最大线程数
                0L, TimeUnit.MILLISECONDS, // 线程空闲时间
                new LinkedBlockingQueue<Runnable>() // 任务队列
        );

 1. 调用execute()

// 使用execute方法提交任务,execute方法不返回结果,适用于不需要返回值的任务
        executor.execute(() -> {
            System.out.println("使用execute方法创建的线程正在运行,线程名: " + Thread.currentThread().getName());
        });

 execute只能提交Runnable任务,因此无返回值

2. 调用submit()方法

// 提交任务给线程池执行,返回一个Future对象,可以获取任务的执行结果
        Future<?> future = executor.submit(() -> {
            System.out.println("使用线程池创建的第一个线程正在运行,线程名: " + Thread.currentThread().getName());
            return "任务执行结果";
        });
        try {
            // 尝试获取submit方法提交任务的结果
            Object result = future.get();
            System.out.println("submit方法提交的任务执行结果: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

submit可以提交Runnable任务或Callable任务,Callable任务可以获得返回值

五、补充的小知识

5.1 核心线程也可以自动回收

核心线程是默认不回收的,但也可以设置回收:

allowCoreThreadTimeOut属性设为 true 就可以跟临时线程一样空闲定时回收了

但是注意:核心线程的本意就是减小线程创建和销毁的资源消耗,如果频繁回收、创建就失去了它的意义

5.2 空闲的核心线程是什么状态

核心线程一般是不会回收的,而要执行任务的时候会拿来直接运行,因为有同学会任务它在空闲时是就绪态。

其实是waiting,等待状态

如果设置了allowCoreThreadTimeOut=true,就是timed_waiting 超时等待。

我们要明白就绪态的意义:逻辑上正在运行,只是CPU没在处理,可能几毫秒后就运行了

而运行态:逻辑上在运行,CPU也恰好在处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值