Bootstrap

线程池的概念和创建

一,什么是线程池

线程池是在应用程序启动时创建一定数量的线程,并将它们保存在线程池中。当需要执行任务时,从线程池中获取一个空闲的线程,将任务分配给该线程执行。当任务执行完毕后,线程将返回到线程池,可以被其他任务复用。

二,线程池的运行机制

1. 当任务到达最大时,线程池管理器会检查线程池中是否有空闲的线程。如果有,则将任务分配给空闲线程执行;如果没有,则进入下一步。
2. 如果线程池中的线程数量未达到最大限制,线程池管理器会创建一个新的线程,并将任务分配给该线程执行。
3. 如果线程池中的线程数量已达到最大限制,并且工作队列未满,则将任务放入工作队列中等待执行。
4. 当线程池中的线程执行完任务后,会从工作队列中获取下一个任务并执行。

三,线程池的优点和缺点 

线程池的主要优点包括:

1,重用线程:线程池会在内部维护一组可重用的线程,避免了频繁地创建和销毁线程的开销,提高了线程的利用率。
2,控制并发度:线程池可以限制并发执行的线程数量,防止系统过载。通过调整线程池的大小,可以控制并发度,避免资源消耗过大。
3,提供线程管理和监控:线程池提供了一些管理和监控机制,例如线程池的创建、销毁、线程状态的监控等,方便开发人员进行线程的管理和调试。
4,提供任务队列:线程池通常会使用任务队列来存储待执行的任务,这样可以实现任务的缓冲和调度。

 四,如何创建线程池

java中其实提供了两种方式:

第一种: 通过工具类完成线程池的创建.[Executors]. 语法简单。但是阿里巴巴不建议使用

第二种: 通过线程池类: ThreadPoolExecutor类. 语法复杂,但是阿里巴巴建议使用。灵活 

线程的根接口: Executor. 里面只有一个方法: execute

子接口: ExecutorService。

 1.Executors

  1. 固定大小的线程池对象newFixedThreadPool

  2. 单一线程池: newSingleThreadExecutor

  3. 可变线程池: newCachedThreadPool

  4. 延迟线程池: newScheduledThreadPool

    public class Test01 {
        public static void main(String[] args) {
            //创建一个固定大小的线程池。返回类型为ExecutorService.
    //        ExecutorService executorService = Executors.newFixedThreadPool(5);
            //创建单一线程池【池子里面只有一个线程的对象】适合任务顺序执行的。
    //        ExecutorService executorService = Executors.newSingleThreadExecutor();
            //创建可变线程池。【池子中线程的数量会随着任务的大小而变化】
    //        ExecutorService executorService = Executors.newCachedThreadPool();
            //延迟线程池:[指定时间后执行]
            ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
    
            //执行线程任务。Runnable  Callable. Integer.MAX()整数的最大值。
    //        for(int i=0;i<10;i++) {
                //1.必须传递Runnable对象。[1]自己创建一个类实现Runnable接口  [2]匿名内部类对象 [3]lambda表达式: 前提接口必须为函数式接口。
    //            executorService.execute(new My());
    //            executorService.execute(new Runnable() {
    //                @Override
    //                public void run() {
    //                    System.out.println(Thread.currentThread().getName()+"*************");
    //                }
    //            });
                //表示10秒后执行任务代码块。
    //            executorService.schedule(()->{
    //                System.out.println(Thread.currentThread().getName()+"~~~~~~~~~~~~~~~");
    //            },10, TimeUnit.SECONDS);
                executorService.scheduleAtFixedRate(()->{
                    System.out.println(Thread.currentThread().getName());
                },5,2,TimeUnit.SECONDS);
    //        }
    
            //关闭线程池
    
        }
    }
    2.ThreadPoolExecutor
public class Test02 {
    public static void main(String[] args) {
        //核心参数的意思
        /**
         * int corePoolSize,核心线程数的个数 2
         *  int maximumPoolSize,最大线程数量 5
         * long keepAliveTime, 非核心线程允许空闲的时间
         * TimeUnit unit, 时间的单位
         * BlockingQueue<Runnable> workQueue 堵塞队列中 3
         */
        BlockingQueue<Runnable> workQueue=new ArrayBlockingQueue(5);
        ThreadPoolExecutor poolExecutor=new ThreadPoolExecutor(2,6,10, TimeUnit.SECONDS,workQueue);

        for (int i = 0; i <11; i++) {
            poolExecutor.submit(()->{
                System.out.println(Thread.currentThread().getName()+"~~~~~~~~~~~~~~~~");
            });
        }
    }
}

 总结:

Executors类中封装好的创建线程池的方法使用方便,但是也有其局限性和风险性,所以我们可以使用 ThreadPoolExecutor 类中的构造方法手动创建线程池的实例, 从而可以根据我们的使用情况来指定参数,满足使用的同时又能规避风险。

;