线程池原理

七、线程池:

线程池:三大方法、7大参数、4种拒绝策略

1、池化技术

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-66CzkK6l-1617852315831)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\image-20210205010647428.png)]

2、线程池相关API:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qLN1eEcO-1617852315841)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\image-20210205010815473.png)]

3、三大方法:

阿里巴巴手册对线程池强制要求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yXHcIOpI-1617852315845)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\image-20210205010953313.png)]

// Executors 工具类、3大创建线程的方法  利用该工具类来创建线程池
public class Demo01 {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();// 单个线程
    // ExecutorService threadPool = Executors.newFixedThreadPool(5); // 创建一个固定的线程池的大小
    // 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();
        }
    }
}

4、七大参数

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,// 阻塞队列
                              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;
    }

七大参数的含义

  • int corePoolSize, // 核心线程池大小,平时正常在用的线程数
  • int maximumPoolSize, // 最大核心线程池大小,当阻塞队列满了,核心线程满了后触发
  • long keepAliveTime, // 超时了没有人调用就会释放 (当非核心线程空闲了,没有被调用了,前面核心线程可以解决一切问题了,就会释放那些非核心线程)
  • TimeUnit unit, // 超时单位
  • BlockingQueue workQueue, // 阻塞队列
  • ThreadFactory threadFactory, // 线程工厂:创建线程的,一般不用动
  • RejectedExecutionHandler handle // 拒绝策略

银行例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oGWnSLQi-1617852315854)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\image-20210205012312964.png)]

解释:

核心线程数10,最大线程数30,keepAliveTime是3秒

随着任务数量不断上升,线程池会不断的创建线程,直到到达核心线程数10,就不创建线程了,

这时多余的任务通过加入阻塞队列来运行,

当任务个数超出阻塞队列长度+核心线程数时,

这时不得不扩大线程个数来满足当前任务的运行,这时就需要创建新的线程了(最大线程数起作用),上限是最大线程数30

那么超出核心线程数10并小于最大线程数30的可能新创建的这20个线程相当于是“借”的,如果这20个线程空闲时间超过keepAliveTime,就会被退出

当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,有以下四种策略

5、四种拒绝策略

/**
* new ThreadPoolExecutor.AbortPolicy() // 银行满了,还有人进来,不处理这个人的,抛出异常
* new ThreadPoolExecutor.CallerRunsPolicy() // 哪来的去哪里!比如main线程进来的,在线程池中最大线程数加队列最大数满了,就返回给main线程去执行
* new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
* new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!
*/

6、自定义线程池

package com.kuang.pc;// Executors 工具类、3大方法

import java.util.concurrent.*;

/**
 四种拒绝策略
 * new ThreadPoolExecutor.AbortPolicy() // 银行满了,还有人进来,不处理这个人的,抛出异
 * 常
 * new ThreadPoolExecutor.CallerRunsPolicy() // 哪来的去哪里!
 * new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
 * new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会
 * 抛出异常!
 
 七大参数:
 * int corePoolSize, // 核心线程池大小,平时正常在用的线程数
 * int maximumPoolSize, // 最大核心线程池大小,当阻塞队列满了,核心线程满了后触发
 * long keepAliveTime, // 超时了没有人调用就会释放 (当非核心线程空闲了,没有被调用了,前面核心线程可以解决一切问题了,就会释放那些非核心线程)
 * TimeUnit unit, // 超时单位
 * BlockingQueue<Runnable> workQueue, // 阻塞队列
 * ThreadFactory threadFactory, // 线程工厂:创建线程的,一般不用动
 * RejectedExecutionHandler handle // 拒绝策略)
 */
public class Demo01 {
    public static void main(String[] args) {
	    // 自定义线程池!工作 ThreadPoolExecutor
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardOldestPolicy()); //队列满了,尝试去和最早的竞争,也不会抛出异常!
        try {
            // 最大承载:Deque + max
            // 超过 RejectedExecutionException
            for (int i = 1; i <= 9; i++) {// 每次队列满了,就创建一个线程。然后又一个任务进来队列,队列满了,就再创建一个线程,直到达到最大的承载:队列的最大长度+线程池最大线程数,这个时候就会根据拒绝策略处理再次进来的任务。
                // 使用了线程池之后,使用线程池来创建线程
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + " ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 线程池用完,程序结束,关闭线程池
            threadPool.shutdown();
        }
    }
}

7、池的最大的大小

了解:IO密集型,CPU密集型:(调优)

package com.kuang.pool;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

// Executors 工具类、3大方法

/** 
 * new ThreadPoolExecutor.AbortPolicy() // 银行满了,还有人进来,不处理这个人的,抛出异常
 * new ThreadPoolExecutor.CallerRunsPolicy() // 哪来的去哪里!比如main线程进来的,在线程池中最大线程数加队列最大数满了,就返回给main线程去执行
 * new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
 * new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会抛出异常!
 */
public class Demo01 {
    public static void main(String[] args) {
        // 自定义线程池!工作 ThreadPoolExecutor

        // 最大线程到底该如何定义
        // 1、CPU 密集型,几核,就是几,可以保持CPu的效率最高!
        // 2、IO  密集型   > 判断你程序中十分耗IO的线程,
        // 程序   15个大型任务  io十分占用资源!

        // 获取CPU的核数
        System.out.println(Runtime.getRuntime().availableProcessors());

        List  list = new ArrayList();

        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                Runtime.getRuntime().availableProcessors(),
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardOldestPolicy());  //队列满了,尝试去和最早的竞争,也不会抛出异常!
        try {
            // 最大承载:Deque + max
            // 超过 RejectedExecutionException
            for (int i = 1; i <= 9; i++) {
                // 使用了线程池之后,使用线程池来创建线程
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" ok");
                });
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 线程池用完,程序结束,关闭线程池
            threadPool.shutdown();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值