java并发编程重点之线程池详解(源码+示例)

线程池:三大方法,七大参数,四种拒绝策略
线程池,首先最要记住上面的话
池化技术

程序的运行,本质占用系统的资源!优化资源的使用!–>池化技术

线程池,连接池,内存池,对象池…

池化技术:事先准备好一些资源,有人要用就来我这拿,用完之后还给我.

线程池的好处:

1.降低资源的消耗

2.提高响应的速度

3.方便管理

总结:线程复用,控制最大并发数,管理线程

//最简单的线程池创建线程
ExecutorService threadpool = Executors.newSingleThreadExecutor();//单个线程

  for (int i = 0; i < 10; i++) {
            threadpool.execute(()->{});}
package com.qiu.pool;
//Executors工具类3大方法
//使用了线程池之后,就要用线程池来创建线程
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo01 {
    public static void main(String[] args) {
        //ExecutorService threadpool = Executors.newSingleThreadExecutor();//单个线程
//ExecutorService threadpool = Executors.newFixedThreadPool(100);//创建一个固定的线程池的大小
ExecutorService threadpool = Executors.newCachedThreadPool();//可伸缩的,遇强则强,遇弱则弱
        try {
        for (int i = 0; i < 100; i++) {
            threadpool.execute(()->{
                System.out.println(Thread.currentThread().getName()+"ok");
            });
        }}catch (Exception e){
            e.printStackTrace();
        }finally {
            //线程用完,程序结束,关闭线程池
            threadpool.shutdown();
        }}
}

三大方法:

ExecutorService threadpool = Executors.newSingleThreadExecutor();//单个线程
ExecutorService threadpool = Executors.newFixedThreadPool(100);//创建一个固定的线程池的大小
ExecutorService threadpool = Executors.newCachedThreadPool();//可伸缩的,遇强则强,遇弱则弱

七大参数

源码分析:
newSingleThreadExecutor
在这里插入图片描述

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

newFixedThreadPool

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

newCachedThreadPool

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,//约等于21亿
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

本质:开启线程,调用了是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.acc = System.getSecurityManager() == null ?
            null :
            AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

long keepAliveTime,//超时没有线程进来执行的话,就会关掉这个核心线程
  下面举一个具体的实例来加深理解
  银行办理业务:先进来的人在窗口办理业务(对应先来的线程进入线程池)
  开放的柜台满人之后,接下来近来的人就会在候客区就坐.(对应核心线程池全部占用后,会去阻塞队列)
  如果此时还有人进来办理业务就会开放更多的窗口(对应还有更多的线程进来的话,就会扩大最大核心线程数.),
  如果说这个时候所有窗口都满了的话,就只能通知后来的客户去别的地方了(对应线程池会使用拒绝策略去阻止线程进来)
在这里插入图片描述

手动创建一个线程池
在这里插入图片描述

四种拒绝策略

  • new ThreadPoolExecutor.AbortPolicy());//银行满了,还有人进来,不处理这个人了,抛出异常

  • new ThreadPoolExecutor.CallerRunsPolicy());//哪来的,去哪里!(main线程来的,就会去main线程执行)都会执行到,不会抛出异常.

  • new ThreadPoolExecutor.DiscardPolicy());//队列满了不会抛出异常,但是会丢掉任务.

  • new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,尝试去和最早的竞争,也不会抛出异常

在这里插入图片描述
代码:

package com.qiu.pool;
//Executors工具类3大方法
//使用了线程池之后,就要用线程池来创建线程
import java.util.concurrent.*;

/**

 * new ThreadPoolExecutor.AbortPolicy());//银行满了,还有人进来,不处理这个人了,抛出异常
   *new ThreadPoolExecutor.CallerRunsPolicy());//哪来的,去哪里!(main线程来的,就会去main线程执行)都会执行到,不会抛出异常.
    *new ThreadPoolExecutor.DiscardPolicy());//队列满了不会抛出异常,但是会丢掉任务.

 * new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,尝试去和最早的竞争,也不会抛出异常
   *
    */
   public class Demo02 {
   public static void main(String[] args) {
       ExecutorService threadpool = new ThreadPoolExecutor(2,
               5,
               3,
               TimeUnit.SECONDS,
               new LinkedBlockingQueue<>(3),Executors.defaultThreadFactory(),//new ThreadPoolExecutor.AbortPolicy());//银行满了,还有人进来,不处理这个人了,抛出异常//new ThreadPoolExecutor.CallerRunsPolicy());//哪来的,去哪里!(main线程来的,就会去main线程执行)都会执行到,不会抛出异常.//new ThreadPoolExecutor.DiscardPolicy());//队列满了不会抛出异常,但是会丢掉任务.
   ​            
   ​            new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,尝试去和最早的竞争,也不会抛出异常try {//最大承载的是队列加最大核心线程:3+5 = 8for (int i = 1; i < 100; i++) {
   ​            threadpool.execute(()->{
   ​                System.out.println(Thread.currentThread().getName()+"ok");});}}catch (Exception e){
   ​        e.printStackTrace();}finally {//线程用完,程序结束,关闭线程池
   ​        threadpool.shutdown();}

   }
   }

由于这个拒绝策略是默认的,所以可以在自定义的时候,可以写,也可以不写,不写那就是默认:
在这里插入图片描述在这里插入图片描述

在这里插入图片描述 小结:
最大线程到底该如何定义(调优)

1.CPU密集型 看电脑核心.几个核心就是几条线程可以同时执行.保证CPU效率最高

Runtime.getRuntime().availableProcessors()

2.IO密集型:判断你的程序中十分耗IO的线程数为多少,一般设置两倍

一个程序,15个大型任务,io十分占用资源!

原创文章 32 获赞 52 访问量 637

猜你喜欢

转载自blog.csdn.net/qq_42400763/article/details/105827682