首页 > 其他分享 >线程池创建的几种方式

线程池创建的几种方式

时间:2024-08-15 11:07:07浏览次数:11  
标签:Executors 创建 void private 几种 线程 执行 public

线程池的创建⽅法总共有 7 种,但总体来说可分为 2 类:

  1. 通过 ThreadPoolExecutor 创建的线程池;
  2. 通过 Executors 创建的线程池

前置步骤

public class ThreadTask implements Runnable{

    Logger logger = LoggerFactory.getLogger(ThreadDemo.class);

    private String taskName;

    public String getTaskName() {
        return taskName;
    }

    public void setTaskName(String taskName) {
        this.taskName = taskName;
    }

    public ThreadTask(String name) {
        this.setTaskName(name);
    }

    @Override
    public void run() {
        logger.info("线程-----------{},执行",taskName);
    }
}

public class FixedThreadDemo extends ThreadTask {

    Logger logger = LoggerFactory.getLogger(ThreadDemo.class);

    private Boolean isAdd ;

    private static Integer count = 0;

    public FixedThreadDemo(String name,Boolean isAdd ) {
        super(name);
        this.isAdd = isAdd;
    }

    private  ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        lock.lock();
        for (int i = 0 ; i < 100;i++){
            if (isAdd){
                count++;
            }else {
                count--;
            }
            logger.info("线程{}--------运行,执行模式:{},执行结果:{}",this.getTaskName(),isAdd?"加线程":"减线程",count);
        }
        lock.unlock();
    }
}


Executors 创建线程池

newFixedThreadPool()

Executors.newFixedThreadPool:创建⼀个固定⼤⼩的线程池,可控制并发的线程数,超出的线程会在队列中等待,直到一个线程可用。如果任何线程在关闭之前的执行过程中由于失败而终止,如果需要执行后续任务,则会有一个新线程取代它的位置。在显式关闭池之前,池中的线程将一直存在。

public class FixedThreadPool {

    private ExecutorService executors;

    private static Logger logger = LoggerFactory.getLogger(FixedThreadPool.class);

    @PostConstruct
    public void init(){
        // 参数 1、表示池中允许存在的最大线程数
        // 参数 2、表示一个线程,自己创建的,可以不用,主要用来记录日志
        executors = Executors.newFixedThreadPool(2,r -> {
            logger.info("创建线程:{} ",r.hashCode());
            Thread thread = new Thread(r);
            return thread;
        });
    }

    // 自定义方法,用于执行线程任务
    // 使用submit可以执行有返回值的任务或者是无返回值的任务;而execute只能执行不带返回值的任务。 
    public void executor(ThreadTask threadTask){
        executors.submit(threadTask);
    }

}

测试:
image

期望值:0 实际结果:0

由于创建线程池指定了 最大线程数是 2,当我在线程池中去加入线程的时候,此时符合2的场景,第三个线程会等待前两个线程中其中一个结束后才会执行。

newCachedThreadPool()

Executors.newCachedThreadPool:创建⼀个可缓存的线程池,若线程数超过处理所需,缓存⼀段时间后会回收,若线程数不够,则新建线程;

public class CachedThreadPool {


    private static Logger logger = LoggerFactory.getLogger(CachedThreadPool.class);

    private ExecutorService executorService;

    public void init(){
        executorService = Executors.newCachedThreadPool(t->{
            logger.info("可缓存的线程池{}",t.hashCode());
            return new Thread(t);
        });
    }

    // 自定义方法,用于执行线程任务
    // 使用submit可以执行有返回值的任务或者是无返回值的任务;而execute只能执行不带返回值的任务。
    public void executor(ThreadTask threadTask){
        executorService.submit(threadTask);
    }
}

执行结果 0

newSingleThreadExecutor()

Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执⾏顺序;

/**
 * @author zhangguangfeng
 * @date 2024/8/15
 * 创建单个线程数的线程池,它可以保证先进先出的执⾏顺序;
 */
public class SingleThreadPool {

    private static Logger logger = LoggerFactory.getLogger(SingleThreadPool.class);

    private ExecutorService executorService;

    public void init(){
        executorService = Executors.newSingleThreadExecutor(t->{
            logger.info("可执⾏顺序的线程池{}",t.hashCode());
            return new Thread(t);
        });
    }

    // 自定义方法,用于执行线程任务
    // 使用submit可以执行有返回值的任务或者是无返回值的任务;而execute只能执行不带返回值的任务。
    public void executor(ThreadTask threadTask){
        executorService.submit(threadTask);
    }
}
    public static void main(String[] args) {

        ThreadTask task1 = new FixedThreadDemo("线程1",Boolean.TRUE);
        ThreadTask task2 = new FixedThreadDemo("线程2",Boolean.FALSE);

        // 执行顺序的线程池
        SingleThreadPool singleThreadPool = new SingleThreadPool();
        singleThreadPool.init();
        singleThreadPool.executor(task1);
        singleThreadPool.executor(task2);
    }

在这里可以看到,在代码顺序上,先执行task1,后执行task2,查看运行结果是否如此,按照指定顺序执行。
image
可以看到,是按照顺序执行的,假设去设置优先级,是否会打乱这个顺序呢?
并不会打乱这个顺序,原因:如它的设定一样,只存在单个线程在执行,本质上就是单线程的。

newScheduledThreadPool()

Executors.newScheduledThreadPool:创建⼀个可以执⾏延迟任务的线程池;

public class SingleThreadPool {

    private static Logger logger = LoggerFactory.getLogger(SingleThreadPool.class);

    private ScheduledExecutorService scheduledExecutorService;

    public void init(){
        scheduledExecutorService = Executors.newScheduledThreadPool(2,t->{
            logger.info("可延迟任务的线程池{}",t.hashCode());
            return new Thread(t);
        });
    }

    // 自定义方法,用于执行线程任务
    public void executor(ThreadTask threadTask){
        // 提交一个定时任务,在 5 秒后执行
        scheduledExecutorService.schedule(threadTask,5, TimeUnit.SECONDS);
    }


    // 自定义方法,用于执行周期性任务
    public void executorAtFixedRate(ThreadTask threadTask){
        // 提交一个周期性任务,每5秒执行一次,初始延迟1秒
        scheduledExecutorService.scheduleAtFixedRate(threadTask,1,5, TimeUnit.SECONDS);
    }
}

运行结果:
image
可以看到,相隔五秒后才运行。
线程测试 周期任务,初始延迟1s,每个5s周期运行
image

Executors.newSingleThreadScheduledExecutor

创建⼀个单线程的可以执⾏延迟任务的线程池;

Executors.newWorkStealingPool

创建⼀个抢占式执⾏的线程池(任务执⾏顺序不确定)【JDK1.8 添加】

ThreadPoolExecutor

ThreadPoolExecutor:最原始的创建线程池的⽅式,它包含了 7 个参数可供设置,
ThreadPoolExecutor 参数说明
image

详细链接:https://blog.csdn.net/m0_48273471/article/details/124171220

标签:Executors,创建,void,private,几种,线程,执行,public
From: https://www.cnblogs.com/zgf123/p/18360487

相关文章

  • golang gin框架中创建自定义中间件的2种方式总结 - func(*gin.Context)方式和闭包函数
    在gin框架中,我们可以通过2种方式创建自定义中间件:1.直接定义一个类型为 func(*gin.Context)的函数或者方法    这种方式是我们常用的方式,也就是定义一个参数为*gin.Context的函数或者方法。定义的方法就是创建一个参数类型为gin.HandlerFunc【他的原型定义为t......
  • 学习009-01 Create a Standalone Web API Application(创建一个独立的 Web API 应用程
    CreateaStandaloneWebAPIApplication(创建一个独立的WebAPI应用程序)Thistopiccontainsstep-by-stepinstructionsonhowtocreateanapplicationwiththeWebAPI.FormoreinformationontheWebAPI,seethefollowingtopic:BackendWebAPIService......
  • Java 中的线程本地存储(ThreadLocal)机制介绍
    Java中的ThreadLocal是一个用于实现线程本地存储(ThreadLocalStorage,TLS)的机制。它可以为每个线程提供独立的变量副本,使得一个线程中的变量不受其他线程中的变量的影响。ThreadLocal通常用于在多线程环境下避免线程之间共享数据,从而实现线程安全。一、基本用法ThreadLoca......
  • 轻松解析高频面试题: 线程设置数量多少合适?带你面试乱杀
    目录一、前言二、线程数和CPU利用率的小测试三、插入io操作四、线程数和CPU利用率总结五、线程数规划的公式 六、真实程序中的线程数一、前言相信很多小伙伴在刷面试题的时候都看到过一个线程数设置的理论:CPU密集型的程序-核心数+1I/O密集型的程序-核心数......
  • 操作系统-进程创建、同步与锁、通信、调度算法-学习笔记
    1.进程的基础概念1.1进程是什么?定义:进程是操作系统管理的一个程序实例。它包含程序代码及其当前活动的状态。每个进程有自己的内存地址空间,拥有独立的栈、堆、全局变量等。操作系统通过进程来分配资源(如CPU时间、内存等)并管理任务的执行。进程vs程序:程序:静态的代......
  • 进程线程(3)
    线程的概念        线程是存在于进程空间中的,使用进程的资源。创建和调度时空开销都比进程小。进程是资源分配的基本单位。重量级进程。进程空间独立,不能直接通信。线程是系统调度的最小单位。轻量级进程。一般是一个进程中的多个任务。线程可以共享空间,可以直接通信......
  • 探索Delphi的多线程世界:线程与进程的奥秘
    探索Delphi的多线程世界:线程与进程的奥秘在现代软件开发中,多线程和多进程是提高应用性能和响应能力的关键技术。Delphi,作为历史悠久的编程语言,提供了丰富的多线程支持。本文将深入探讨Delphi中的线程与进程的区别,并提供实际代码示例,帮助读者理解这两种并发执行方式的内在机......
  • 《python程序语言设计》2018版第7章第2题创建一个stock类,一个公司股票。创建stock,包含
    使用百分比法计算股票变化值百分比法是计算股票变化值的常用方法。具体操作是:将当前股票价格与前一交易日的股票价格进行比较,计算出价格变动的百分比。公式为:(当前价格-前一交易日价格)/前一交易日价格×100%。这种方法简单明了,可以快速得出股票变化的百分比。......
  • 《python语言程序设计》2018第7章第1题 第2次刷题 创建一个Rectangle类,包括长、宽数据
    uml类图到现在不会弄。此处为main的位置,不是rectangle类的代码。importmathdefmain():width_int=eval(input("EnterRectangle#1width:"))height_int=eval(input("EnterRectangle#1height:"))a=exCode07.Rectangle(width_int,height......
  • QT多线程
    当处理复杂的数据时,此时耗时间,需要多任务处理就需要用到线程了qt中使用线程的方法,自定义一个类继承QThreadQThread类中有个虚函数 voidrun()才是线程中的处理函数我们需要重写该函数但启动线程不能直接调用run函数,需要通过线程类的start()函数来间接调用run函数......