06-线程池(3大方法、7大参数,4种拒绝策略)

池化技术

程序运行的本质:占用系统的资源==》优化资源的使用==池化技术:提前准备好资源,如果需要使用,则到池里用,用完后释放返回给池里以备下次或其他线程使用。
线程池、连接池、内存池、对象池、创建销毁都非常的浪费资源。
优点

  1. 降低资源的消耗
  2. 提高响应的速度
  3. 方便管理
  4. 线程的复用,可以控制最大并发数,管理线程
三大方法
1单个线程池

新建单个线程池


/**
 * @author 
 * @Date 2022/7/26
 * @apiNote
 */
public class TApi {
    public static void main(String[] args) {
        ExecutorService singlePool=Executors.newSingleThreadExecutor();

            try {
                for (int i = 0; i < 100; i++) {
                singlePool.execute(()->{//代替new Thread.start(),利用线程池执行线程
                    System.out.println(Thread.currentThread().getName()+"OK");
                });
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                singlePool.shutdown();//关闭线程池
            }
    }
}

结果:
无论多少个线程处理,都在同一个线程池里面执行。
06-线程池(3大方法、7大参数,4种拒绝策略)_第1张图片

2固定线程池

新建固定个数的线程池


/**
 * @author
 * @Date 2022/7/26
 * @apiNote
 */
public class TApi {
    public static void main(String[] args) {
    //新建5个线程池
        ExecutorService fixedPool=Executors.newFixedThreadPool(5);

            try {
                for (int i = 0; i < 100; i++) {
                    fixedPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"====OK");
                });
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                fixedPool.shutdown();//关闭线程池
            }
    }
}

结果:
无论多少个线程执行,都在5个线程池当中。
06-线程池(3大方法、7大参数,4种拒绝策略)_第2张图片

3灵活线程池

根据系统CPU大小,灵活创建线程池,CPU越好,创建线程池越多。


/**
 * @author
 * @Date 2022/7/26
 * @apiNote
 */
public class TApi {
    public static void main(String[] args) {
        ExecutorService cachedPool=Executors.newCachedThreadPool();

            try {
                for (int i = 0; i < 100; i++) {
                    cachedPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"====OK");
                });
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                cachedPool.shutdown();//关闭线程池
            }
    }
}

结果:
我的电脑当前可以创建最多线程池30个。
06-线程池(3大方法、7大参数,4种拒绝策略)_第3张图片

7大参数

源码:

//单个线程池源码
    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
以下为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;
    }

线程池不允许使用Executor去创建,而是通过ThreadPoolExecutor的方式,这样是为了让我们更好的了解线程池的运行规则,规避资源耗尽的风险。
Executor直接使用弊端为:

  1. FixedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,导致OOM,
  2. CachedThreadPool和SceduledThreadPool:允许创建的线程数量为Integer.MAX_VALUE,可能会创建大量线程,导致OOM,

示例:

  1. 当有两个线程进行时:

/**
 * @author
 * @Date 2022/7/26
 * @apiNote
 */
public class TApi {
    public static void main(String[] args) {
        ExecutorService threadPool =new ThreadPoolExecutor(2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()//线程池满了,阻塞队列满了,进入后不再处理并抛出异常
        );

            try {
                for (int i = 1; i <= 2; i++) {
                    threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"====OK");
                });
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                threadPool.shutdown();
            }
    }
}

结果:
06-线程池(3大方法、7大参数,4种拒绝策略)_第4张图片
分析:当前两个核心线程池在处理

2.当有3个线程进行时


/**
 * @author 
 * @Date 2022/7/26
 * @apiNote
 */
public class TApi {
    public static void main(String[] args) {
        ExecutorService threadPool =new ThreadPoolExecutor(2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()//线程池满了,阻塞队列满了,进入后不再处理并抛出异常
        );

            try {
                for (int i = 1; i <= 3; i++) {
                    threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"====OK");
                });
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                threadPool.shutdown();
            }
    }
}

结果:
06-线程池(3大方法、7大参数,4种拒绝策略)_第5张图片
分析:当前两个核心线程池在处理

3.四个线程:
06-线程池(3大方法、7大参数,4种拒绝策略)_第6张图片
两个核心线程池在处理

4.五个线程:
06-线程池(3大方法、7大参数,4种拒绝策略)_第7张图片
5.六个线程:
06-线程池(3大方法、7大参数,4种拒绝策略)_第8张图片
两个核心线程池外加一个线程池在处理。

6.八个线程
06-线程池(3大方法、7大参数,4种拒绝策略)_第9张图片

7.九个线程
06-线程池(3大方法、7大参数,4种拒绝策略)_第10张图片
当九个线程进行时,超过了设定最大线程池数量(5)+阻塞队列(3)个(8<9),触发拒绝策略abortPolicy,抛出异常。

四种拒绝策略

除去上面的AbortPolicy拒绝策略,以下还有三种:
1.CallerRunPolicy拒绝策略
含义:哪来的回哪去

06-线程池(3大方法、7大参数,4种拒绝策略)_第11张图片
结果:
由主线程发出的,超过设定数量,会返回给主线程。
06-线程池(3大方法、7大参数,4种拒绝策略)_第12张图片
2.DiscardPolicy拒绝策略
06-线程池(3大方法、7大参数,4种拒绝策略)_第13张图片
结果:
06-线程池(3大方法、7大参数,4种拒绝策略)_第14张图片
达到设定线程池的数量8后,队列满后,之后第九个线程会被废弃掉,不抛出异常。

3.DiscardOldestPolicy
06-线程池(3大方法、7大参数,4种拒绝策略)_第15张图片
结果:
达到设定的最大线程数量8,第九个会尝试和第一个竞争,竞争成功会占用第一个,竞争失败就会自动丢弃掉。也不会抛出异常
06-线程池(3大方法、7大参数,4种拒绝策略)_第16张图片
最大线程如何定义

  1. CPU密集型:服务器几核CPU,就定义最大线程池数,如12核CPU就定义线程池数最大数量为12,可以保证CPU利用效率最高
  2. IO密集型:判断程序中十分消耗IO的程序,大于这个就可以

你可能感兴趣的:(JUC并发编程,java,线程池,ExecutorService,拒绝策略)