首页 > 编程语言 >JAVA多线程(二)--线程池

JAVA多线程(二)--线程池

时间:2023-02-18 21:11:19浏览次数:35  
标签:Runnable -- 创建 接口 任务 线程 多线程 ThreadPoolExecutor

JAVA多线程(二)--线程池

一、线程池概念

顾名思义,线程池是管理线程的池子。使用线程池有以下优点:

  • 降低线程创建和销毁的开销。
  • 提高响应速度。用到时创建和直接使用已创建好的线程,速度肯定是不一样的。
  • 提高线程可管理性。线程是稀缺资源,使用线程池可对线程进行统一分配、调优和监控。

二、JUC架构

image

1、Executor接口

Executor 接口是JUC架构的顶级接口,它只包含一个void execute(Runnable command)方法,是一个执行线程的工具。

public interface Executor {
    void execute(Runnable command);
}

2、ExecutorService接口

ExecutorService接口继承于Executor 接口,向外提供了接收异步任务的服务。

public interface ExecutorService extends Executor {

    // 接收单个异步任务
    <T> Future<T> submit(Callable<T> task);
	
    <T> Future<T> submit(Runnable task, T result);

    Future<?> submit(Runnable task);

    // 批量接收异步任务
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;
}

3、AbstractExecutorService抽象类

抽象类,实现了ExecutorService接口

4、ScheduledExecutorService接口

ScheduledExecutorService接口继承了ExecutorService接口,是一个可以完成'延时'和'周期性'任务的调度线程池接口。

5、ThreadPoolExecutor类

ThreadPoolExecutor类继承了AbstractExecutorService抽象类,是线程池中核心实现类。

6、ScheduledThreadPoolExecutor类

ScheduledThreadPoolExecutor类实现了ScheduledExecutorService接口,继承了ThreadPoolExecutor类。拓展实现了延时执行和周期执行等抽象方法。

7、Executors

静态工厂类,它通过静态工厂方法返回ExecutorServiceScheduledExecutorService等线程池示例对象

三、使用Executors静态工厂类创建线程池

1、newFixedThreadPool 固定线程数的线程池

创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。如果所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在执行期间有由于失败导致任何线程终止,那么一个新线程将代替它执行后续任务。在某个线程被显示的关闭之前,池中的线程将一直存在。

弊端:阻塞队列是无界队列,大量任务涌入时,会导致队列很大,容易导致JVM出现OOM异常,即内存溢出。

2、newSingleThreadExecutor 单个线程的线程池

创建一个只有一个线程的线程池。这个线程池可以在线程死后(或发生异常),重新启动一个线程来替代原先的线程继续执行后续任务。

弊端:同固定数量线程池,阻塞队列无界。

3、newCachedThreadPool 缓存线程池

创建一个可根据需要创建新线程的线程池,但是在以前线程可用时将重用它们。当前线程池中有可用线程时将重用已有线程,当线程池中无可用线程将创建新的线程加入到线程池中执行新的任务。终止并移除那些已有60s未被使用的线程。

弊端:线程数没有限制,由于其maximumPoolSize的值为Integer.MAX_VALUE(非常大),可以认为可以无限创建线程,如果任务提交较多,就会造成大量的线程被启动,很有可能造成OOM异常,甚至导致CPU线程资源耗尽

4、newScheduledThreadPool 可调度线程池

创建一个可安排在给定延迟后执行任务的线程池。线程池中包含最小限度固定数量的线程corePoolSize,即使空闲状态也一直存在,除非设置了allowCoreThreadTimeOut。当初始线程不够时会创建新的线程加入线程池,这部分线程会因为限制状态被释放

弊端:线程数不设上限

5、newSingleThreadScheduledExecutor 单个线程的可调度线程池

创建一个corePoolSize 为1的可安排在给定延迟后执行任务的线程池。

弊端:线程数不设上限

6、newWorkStealingPool 工作窃取式线程池

Java8新增的创建线程池方法。实际返回ForkJoinPool对象,创建时如果不设置任何参数,则以当前机器处理器个数作为线程个数,此线程池会并行处理任务,不能保证执行顺序。使用所有可用的处理器作为其目标并行度级别创建一个窃取工作的线程池。
使用场景:能够合理的使用CPU进行对任务操作(并行操作),适合使用在很耗时的任务中。底层用的ForkJoinPool 来实现的。 ForkJoinPool的优势在于,可以充分利用多cpu,多核cpu的优势,把一个任务拆分成多个“小任务”分发到不同的cpu核心上执行,执行完后再把结果收集到一起返回。

四、使用ThreadPoolExecutor创建线程池

其实Executors中除去Java8新加的newWorkStealingPool方法外(调用的ForkJoinPool),其他的创建线程池的方法基本上都是调用了ThreadPoolExecutor的构造函数。
ThreadPoolExecutor提供了一系列属性,供我们根据实际业务来创建合适的线程池;

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;
    }
  • int corePoolSize: 核心线程最大数量,通俗点来讲就是,线程池中常驻线程的最大数量
  • int maximumPoolSize: 线程池中运行最大线程数(包括核心线程和非核心线程)
  • long keepAliveTime: 线程池中空闲线程(仅适用于非核心线程)所能存活的最长时间
  • TimeUnit unit: 存活时间单位,与keepAliveTime搭配使用
  • BlockingQueue<Runnable> workQueue:存放任务的阻塞队列
  • ThreadFactory threadFactory:新线程的产生方式
  • RejectedExecutionHandler handler: 线程池拒绝策略

注:若调用了allowCoreThreadTimeOut(boolean)方法,并且传入了参数true,则keepAliveTime参数所设置的Idle超时策略也将被应用于核心线程

五、向线程池提交任务

1、execute()

  • void execute(Runnable command)

Executor接口中的方法, ThreadPoolExecutor中实现,ScheduledThreadPoolExecutor中重写等。
只能接收Runnable,无返回值

2、submit()

  • <T> Future<T> submit(Callable<T> task)
  • <T> Future<T> submit(Runnable task, T result)
  • Future<?> submit(Runnable task)

这3个submit()方法都是ExecutorService接口中定义的方法, AbstractExecutorService中实现,ScheduledThreadPoolExecutor中重写等。

可以接收Callable``Runnable,有返回值。

3、invokeAny()

批量提交,返回第一个返回值。

4、invokeAll()

批量提交,返回所有返回值。

六、线程池任务调度

七、阻塞队列

八、线程工厂

九、拒绝策略

十、调度器的钩子方法

十、关闭线程池

标签:Runnable,--,创建,接口,任务,线程,多线程,ThreadPoolExecutor
From: https://www.cnblogs.com/code-tong/p/17111768.html

相关文章

  • Mybatisplus----DML编程---多记录操作
    批量处理数据:@TestvoidtestDelete(){//批量按id删除List<Long>list=newArrayList<>();list.add(1626917366924050434L);......
  • 一道挺有意思的题目探究——不稳定的道路
    题目简述:给你一个无向图,n个点,m条边,每条边有两个权值,c和d通过一条边的时间为 c+d/(t+1)  t为当前时刻(后半部分向下取整)可以在任意一个点停留任意时间询问1到n的最......
  • 20230218读书有感
    1.底部形态要研究,否则是摸底 2.关注,否者做不了期货,不是短期价格波动,而是长期周期 3.入场点(足够高低,形态),做错了怎么办,割肉后继续进 4.高点低点是相对的,可以做,或者......
  • 参考iictools源码实现HP203b气压温度传感器读取
    参考i2ctools源码实现HP203B气压温度传感器读取由于开发的设备中要用到HP203B气压温度传感器,此设备要用到i2c协议进行数据的读取,我将以韦东山老师课程为指引,参考经典的i2c......
  • ChatGPT踩坑(We've detected suspicious behavior from phone numbers similar to you
    现象We'vedetectedsuspiciousbehaviorfromphonenumberssimilartoyours.Pleasetryagainlaterorcontactusthroughourhelpcenterathelp.openai.com.......
  • 通过整合lightweight openpose的收获
    1.transformer是对lable和image进行处理。2.训练时图片的批度都是一个大小,验证时可不必遵循。3.paf就是向量图一个x一个y。4.neck是左肩和右肩的关键点。5.最后一个key......
  • 使用 Kitten 编程猫绘制一个魔方
    绘制出的魔方效果如下图所示:在水平方向和Y方向绘制的立方体序列集合,我们前文已经叙述过了,本文主要讨论Z方向也就是俯视方向的立方体集合如何绘制。笔者采用的是Z......
  • 网站返回504排查记录
    tengine配置的全局超时时间是120s,供应商说他们的请求会超过120s。于是我针对这个域名配置了相关的超时时间。配置如下:proxy_connect_timeout600;proxy_send_timeout......
  • 数列的极限
    数列极限的定义      极限中ε的意义: ε在极限讨论中代表的是一个大于0的很小的数,可以任意小,只要不等于零由于这个任意小很模糊,同时又要求ε是一个极小......
  • C语言经典习题(一)
    试验报告(一)1、本实验要求事先编好解决下面问题的程序,然后上机输入程序并调试运行程序。有如下函数:①写程序,输入x的值,输出y相应的值。用scanf函数输入x的值,求y值。②运......