线程池创建的几种方式

线程池的创建⽅法总共有 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

posted @   自学Java笔记本  阅读(85)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示