自学内容网 自学内容网

【JAVA入门】Day48 - 线程池

【JAVA入门】Day48 - 线程池



        我们之前写的代码都是,用到线程的时候再创建,用完之后线程也就消失了,实际上这是不对的,它会浪费计算机的内存和运算资源。
        线程池的出现就是为了解决这个问题,线程池在收到任务后,会派出一个空闲线程进行处理,处理完毕后,该线程又会回到线程池;如果没处理完时又来了新的任务,那么它就再派出一个线程进行处理,但最后,所有的线程都会再次回到线程池,没有产生任何浪费。
        线程池虽然方便,但也是有上限的,这个上限可以由我们自己设置,如果提交任务时池子里没有空闲线程,剩下的线程只能在外等待。

一、线程池的主要核心原理

① 创建一个池子,池子中是空的。
② 提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子。下次再提交任务时,不需要创建新的线程,直接复用已有的线程即可。
③ 如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待。

如果要用代码创建线程池,我们需要用到一个新的工具类——Executors。
在这里插入图片描述

代码实现如下:

package ExecutorsDemos;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MyThreadPoolDemo {
    public static void main(String[] args) {
        /*
            public static ExecutorService newCachedThreadPool()                     创建一个没有上限的线程池
            public static ExecutorService newFixedThreadPool(int nThreads)          创建一个上限为nThreads的线程池
         */

        //1.获取线程池对象
        ExecutorService pool1 = Executors.newCachedThreadPool();

        //2.提交任务
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());

        //3.销毁线程池
        //pool1.shutdown();

        //4.创建一个有上限的线程池
        ExecutorService pool2 = Executors.newFixedThreadPool(3);
      
    }
}

二、自定义线程池

        线程池创建的构造方法 ThreadPoolExecutor() 最多可达7个参数。如果将线程池比作经营饭店,那么这七个参数对应下面七种要素。
在这里插入图片描述
        自定义线程池的运行情况和你提交的任务数量有关,假设有一个自定义线程池,核心线程有3个,临时线程有3个,现在根据不同任务数量进行处理。
1.提交3个任务,线程池只需动用3个核心线程分别执行即可。
在这里插入图片描述

2.提交5个任务时,此时前3个任务分别被3个核心线程包揽,但是剩下两个任务并没有核心线程可以支持,这时候线程池却不创建临时线程来干活,因此后2个任务只能排队等待。

在这里插入图片描述
3.提交8个任务时,此时前3个任务被3个核心线程包揽,然后剩下3个任务去队列里排队,把长度为3的队列也占满了,此时还有2个任务没有去处,这个时候线程池才会创建2个临时线程来处理任务七和任务八。
在这里插入图片描述
由这个案例可以知道,先提交的任务不一定优先执行。
4.提交10个任务时,前3个任务被3个核心线程包揽,后3个任务被放入队伍排队,再3个任务被临时线程包揽,此时还剩1个任务,此时这个任务没有线程可以处理,只能触发任务拒绝策略。

在这里插入图片描述
Java 中默认的策略就是:丢弃任务并抛出异常,其他三个策略了解一下就行。
在这里插入图片描述

        自定义线程池的构造方法代码实现如下所示:

package ExecutorsDemos;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExecutorDemo1 {
    /*
        ThreadPoolExecutor
        参数一:核心线程数量
        不能小于0
        参数二:最大线程数
        不能小于等于0,最大数量>=核心线程数量
        参数三:空闲线程最大存活时间
        不能小于0
        参数四:时间单位
        用TimeUnit指定
        参数五:任务队列
        不能为null
        参数六:创建线程工厂
        不能为null
        参数七:任务的拒绝策略
        不能为null
     */
    public static void main(String[] args) {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
                3, //核心线程数量,不能小于0
                6,  //最大线程数,不能小于0,最大数量 >= 核心线程数
                60,  //空闲线程最大存活时间
                TimeUnit.SECONDS,   //时间单位,这里是一个常量"秒"
                new ArrayBlockingQueue<>(3),    //阻塞队列,长度为3
                Executors.defaultThreadFactory(),     //创建线程工厂
                new ThreadPoolExecutor.AbortPolicy()  //任务的拒绝策略,它是一个内部类
        );
    }
}

三、线程池的大小

        线程池多大合适呢?这个我们一般有专门的公式。
在这里插入图片描述
        一个4核8线程的CPU,最大并行数是8。
在这里插入图片描述


原文地址:https://blog.csdn.net/oo00Z00oo/article/details/142377611

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!