线程池基础入门

线程池的状态

线程池的5种状态
RUNNING: 线程池处在 RUNNING 状态时,能够接收新任务,以及对已添加的任务进行处理。该状态是线程池的初始状态,线程池一旦被创建,就处于 RUNNING 状态
SHUTDOWN: 线程池处于 SHUTDOWN 状态时,不接收新任务,但能处理等待队列中的任务。线程池在 RUNNING 状态下,调用 shutdown() 方法,会变成 SHUTDOWN 状态。
STOP: 线程池处于 STOP 状态时,不接收新任务,不再处理等待队列中的任务,并且会中断正在处理的任务,线程池在 RUNNING 状态下,调用 shutdownNow() 方法,变为 STOP 状态
TIDYING: 所有的任务都销毁了,工作线程数量为0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated()
线程池在 SHUTDOWN 状态时,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN 状态变为 TIDYING 状态;
线程池在 STOP 状态时,线程池中执行的任务为空时,就会由 STOP 状态变为 TIDYING 。
TERMINATED: terminated() 方法执行之后,线程池彻底终止,就变成 TERMINATED 状态。
在这里插入图片描述

在这里插入图片描述


ThreadPoolExecutor - 构造方法

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) 
  • corePoolSize 核心线程数(最多保留的线程数)
  • maximumPoolSize 最大线程数目
  • keepAliveTime 线程执行完任务后的空闲时间 - 针对救急线程
  • unit 时间单位 - 针对救急线程
  • workQueue 阻塞队列
  • threadFactory 线程工厂 - 可以为线程创建时起个好名字
  • handler 拒绝策略

在线程池中分为核心线程救急线程,救急线程一般是在任务阻塞队列(有界队列)满了之后才会被创建的。
corePoolSIze + 救急线程数 <= maximumPoolSize 。
救急线程存在生存时间(由keepAliveTime 决定),核心线程则没有。
当救急线程也满了(都在执行任务),如果再来一个任务,就会执行拒绝策略

Executors类和ThreadPoolExecutor都是util.concurrent并发包下面的类, Executos下面的newFixedThreadPool、newScheduledThreadPool、newSingleThreadExecutor、newCachedThreadPool底层的实现都是用的ThreadPoolExecutor(构造时设置不同的参数)实现的,所以ThreadPoolExecutor更加灵活。


Executors - 固定大小的线程池

在这里插入图片描述

特点:

  • 核心线程数 = 最大线程数 (没有救急线程被创建),因此无需超时时间
  • 阻塞队列是无界的,可以放任意数量的任务

测试代码:

 public static void main(String[] args) {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);

        for (int i=0; i<5; i++){
            int j = i;
            fixedThreadPool.execute(()->{
                System.out.println("当前线程是"+Thread.currentThread().getName()+" --------"+j);
            });
        }

    }

执行结果:
在这里插入图片描述

适用于任务量已知,相对耗时的任务


Executors - 定时线程池

测试代码:

import java.util.concurrent.*;

public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);

        /**
         * 延时执行任务(执行一次)
         */
        pool.schedule(()->{
            System.out.println("延时执行任务task1");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },1,TimeUnit.SECONDS);
        pool.schedule(()->{
            System.out.println("延时执行任务task2");
        },1,TimeUnit.SECONDS);

        /**
         * 以一定的速率执行任务(执行一次)
         */
        pool.scheduleAtFixedRate(()->{
            System.out.println("以固定的速率执行------scheduleAtFixedRate");
        },1,3,TimeUnit.SECONDS);

        /**
         * 以一定的延时执行任务(执行一次)。跟固定速率不同,这个延时以上个任务结束为坐标
         */
        pool.scheduleWithFixedDelay(()->{
            System.out.println("以固定的延时执行------scheduleAtFixedRate");
        },1,3,TimeUnit.SECONDS);
    }
}

执行结果:
在这里插入图片描述


Executors - 带缓冲线程池

在这里插入图片描述

特点:

  • 核心线程数是0,最大线程数是Integer.MAX_VALUE,救急线程的空闲生存时间是60s
    • 全部都是救急线程(60s后可以回收)
    • 救急线程可以无限创建
  • 队列采用SynchronousQueue实现特点是,它没有容量(可以理解是容量为0)

整个线程池表现为线程数会根据任务量不断增加,没有上限,当任务执行完毕,空闲一分钟后释放线程。适合做任务比较密集,但每个任务执行时间较短的情况。


Executors - 单线程线程池

在这里插入图片描述
使用场景:
希望多个任务排列执行。线程数固定为1,任务数大于1,会放入无界队列排队。任务执行完毕,这个唯一的线程也不会被释放。

区别:

  • newSingleThreadExecutor与自己创建一个线程
    • 自己创建一个单线程串行执行任务,如果任务执行失败而终止那么没有任何补救措施,而线程池会新建一个线程,保证线程池的正常运行
  • newSingleThreadExecutor与newFixedThreadPool(1)
    • 【newSingleThreadExecutor】只对外暴露ExecutorService接口,一次不能调用ThreadPoolExecutor中特有的方法
    • 【newFixedThreadPool】对外暴露的是ThreadPoolExecutor对象,可以强转后调用setCorePoolSize等方法进行修改

线程池常用方法

提交任务

1、 void execute(Runnable runnable);

单纯的执行任务,没有返回结果。

ExecutorService executorService = Executors.newFixedThreadPool(2);
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("Runnable输出信息");
        }
    };
    executorService.execute(runnable);
// lamda写法
executorService.execute(()->{ System.out.println("Runnable输出信息");});

2、 Future submit(Callable task);
提交任务task,用返回值Future获取任务执行结果

ExecutorService executorService = Executors.newFixedThreadPool(2);
        Callable callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return "带返回值的执行任务1";
            }
        };
        Future future1 = executorService.submit(callable);
        System.out.println(future1.get());
        // lamda写法
        Future<String> future2 = executorService.submit(() -> {
            return "带返回值的执行任务2";
        });
        System.out.println(future2.get());

3、 List<Future> invokeAll(Collection<? extends Callable> tasks)
throws InterruptedException;

提交tasks中所有的任务,接收一个集合对象(里面是Callsble对象),返回值是一个集合对象(里面是Future对象)

ExecutorService executorService = Executors.newFixedThreadPool(2);
        List<Future<Object>> futures = executorService.invokeAll(Arrays.asList(
                () -> {
                    return "invokeAll任务结果1";
                },
                () -> {
                    return "invokeAll任务结果2";
                },
                () -> {
                    return "invokeAll任务结果3";
                }
        ));
        futures.forEach(f -> {
            try {
                System.out.println(f.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });

关闭线程池

1、 shutdown()
线程池的状态变为SHUTDOWN,不会接收新的任务,但已提交的任务会执行完,此方法不会阻塞调用线程的执行
在这里插入图片描述
2、 shutdownNow()
线程池的状态变为STOP,不会接收新任务,会将队列中的任务返回,并用interrupt的方式中断正在执行的任务
在这里插入图片描述

查看线程池状态的方法

1、isShutDown()
当调用shutdown()或shutdownNow()方法后返回为true。
2、isTerminated()
当调用shutdown()方法后,并且所有提交的任务完成后,包括任务队列里面的任务返回为true。当调用shutdownNow()方法后,成功停止后返回为true。

如果线程池任务正常完成,都为false

一般可以利用shutDown()与isTerminated()来配合,实现等待线程池中的任务完成之后再去执行后面的逻辑
如下代码:

/*创建任务*/
Runnable runnable = new Runnable() {
    public void run() {
        // 执行任务xxxx
    }
};

/*创建线程池*/
ExecutorService executorService = Executors.newFixedThreadPool(10);

long end;
long start = System.currentTimeMillis();
/*执行任务*/
for (int i=0; i<100; i++) {
    executorService.execute(runnable);
}
// 关闭线程池不会接收新的任务 但已提交的任务会执行完 shutdown()此方法不会阻塞调用线程的执行
executorService.shutdown();
while (true) {
    if(executorService.isTerminated()){
         end = System.currentTimeMillis();
         break;
    }
}
System.out.println("用时"+(end-start)+"毫秒");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

coderzpw

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

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

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

打赏作者

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

抵扣说明:

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

余额充值