JUC——线程池

先说思想

池化技术是一种设计思想:

预先创建好资源并保留,避免资源的频繁创建 和 销毁 而浪费CPU资源。

常见场景:

  • 线程池
  • 对象池
  • 连接池

线程池的三大方法


单一线程的线程池

public static void main(String[] args) {
    
    
    //创建单一(大小)线程池
    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    try {
    
    
        for(int i = 1;i <= 10; i++){
    
    
            //利用线程池创建线程
            singleThreadExecutor.execute(()->{
    
    
                System.out.println(Thread.currentThread().getName());
            });
        }
    } finally {
    
    
        //关闭线程池
        singleThreadExecutor.shutdown();
    }
}

执行结果:

在这里插入图片描述


自定义线程池线程数

public static void main(String[] args) {
    
    
    //创建大小为 5 的线程池
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
    try {
    
    
        for(int i = 1;i <= 10; i++){
    
    
            //利用线程池创建线程
            fixedThreadPool.execute(()->{
    
    
                System.out.println(Thread.currentThread().getName());
            });
        }
    } finally {
    
    
        //关闭线程池
        fixedThreadPool.shutdown();
    }
}

执行结果:
自定义线程池线程数执行结果


线程池内线程数不限(只受设备影响)

public static void main(String[] args) {
    
       
    //创建大小可变的线程池
	ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    try {
    
    
        for(int i = 1;i <= 10; i++){
    
    
            //利用线程池创建线程
            cachedThreadPool.execute(()->{
    
    
                System.out.println(Thread.currentThread().getName());
            });
        }
    } finally {
    
    
        //关闭线程池
        cachedThreadPool.shutdown();
    }
}

执行结果:
不限流线程池执行结果

三大方法源码审查

//单一
public static ExecutorService newSingleThreadExecutor() {
    
    
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

//可设置
public static ExecutorService newFixedThreadPool(int nThreads) {
    
    
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
}

//任意
public static ExecutorService newCachedThreadPool() {
    
    
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
}

他们三个都调用了 ThreadPoolExecutor 这个方法:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    
    
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}

接着 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.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

到这我们就能发现,其实开始说的线程池三大方法只是对 ThreadPoolExecutor 的进一步简单封装

简单的封装意义就不大了,虽然可以少写几行代码,但它让代码看起来不直观了,并且伴随着安全隐患。

所以我们要自己定义线程池,这样既直观又安全。

自定义线程池(推荐)

//自定义线程池 ThreadPoolExecutor,这样创建比较安全,并且容易阅读

/**最大线程数到底如何定义
 * CPU 密集型: 逻辑处理核数 是几就是几
 * 获得CPU核数
 * System.out.println(Runtime.getRuntime().availableProcessors());
 *
 * IO 密集型: 最大线程数 一定要大于 项目中非常占资源的IO任务数
 * (这样就能保证,在所有IO任务执行的时候,不会阻塞其他的进程执行。)
 */


//CPU密集型的写法(创建自定义线程池)
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
        2,//正在营业的
        Runtime.getRuntime().availableProcessors(),//最多营业人数
        3,//3秒钟没人来,(5-2)这3个人就休息了
        TimeUnit.SECONDS,//等待时间单位
        new LinkedBlockingQueue<>(4),//候客区
        Executors.defaultThreadFactory(),//线程创建工程
        //new ThreadPoolExecutor.AbortPolicy()//默认拒绝策略:人满了(max_5 + queue_3 = 8_承载量)再来就抛出异常。
        //new ThreadPoolExecutor.CallerRunsPolicy()//哪来的去哪里,(这里是从 main线程过来的,所以超出的进程会被打回main线程)
        //new ThreadPoolExecutor.DiscardPolicy()//队列满了不会抛出异常,直接不管了(丢掉任务)
        new ThreadPoolExecutor.DiscardOldestPolicy()//队列满了不会抛出异常,但会尝试去和最早的线程竞争。
);
try {
    
    
    for (int i = 1; i <= 5; i++) {
    
    
        threadPoolExecutor.execute(()->{
    
    
            try {
    
    
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
        });
    }
} finally {
    
    
    threadPoolExecutor.shutdown();
}

猜你喜欢

转载自blog.csdn.net/weixin_43415201/article/details/117258156