10.彻底搞懂Java线程池

彻底搞懂Java线程池

文章目录

    • 彻底搞懂Java线程池
    • 三大方法
      • 三大方法代码实现
    • 7大参数
      • 三大方法源码分析
      • 七大参数图解:
      • 手动创建一个线程池
    • 4种拒绝策略
    • 小结和拓展

彻底搞懂线程池只需要知道线程池中:三大方法、7大参数,4中拒绝策略

池化技术

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

线程池,连接池,对象池

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

线程池的好处:

1.降低资源的消耗

2.提高响应速度

3.方便管理

线程复用、可以控制最大并发数、管理线程

三大方法

三大方法

以下是阿里巴巴开发手册注意事项:

10.彻底搞懂Java线程池_第1张图片

三大方法代码实现

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

//Executors 简单理解为工具类 、三大方法
//使用了线程池之后,使用线程池来创建线程
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 < 10; i++) {
     
                threadPool.execute(()->{
     
                    System.out.println(Thread.currentThread().getName()+"  OK");
                });
            }
        } catch (Exception e) {
     
            e.printStackTrace();
        }finally {
     
            //线程池用完,程序结束,关闭线程池
            threadPool.shutdown();
        }

    }
}

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()	
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;
}

七大参数图解:

模拟银行办理业务的场景:核心线程池大小–阻塞队列大小–最大线程池大小–拒绝策略

核心线程池大小数就是开的窗口数,假设一个常见,银行开始只开放了两个窗口,2个顾客已经占用,后面又来了3个客人,这3个客人就需要在候客区等待,这个候客区就是阻塞队列,如果阻塞队列容量大小为3,那说明这个时候候客区也满了,那么银行的其他窗口也要开放,又开放了3个窗口,一共就有5个窗口了,5就是最大线程池大小,如果又来了3个顾客,就占满了所有窗口,候客区也慢了,如果再来一个顾客,就会实施拒绝策略。

10.彻底搞懂Java线程池_第2张图片

手动创建一个线程池

public class Demo02 {
     
    public static void main(String[] args) {
     
        //自定义线程池! 工作中使用ThreadPoolExecutor自定义线程池,不用Executors工具类的线程池,不安全,OOM
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,//核心线程池大小
                5,//最大线程池大小
                3,//超时时间,超过后释放线程
                TimeUnit.SECONDS,//超时单位
                new LinkedBlockingQueue<>(3),//阻塞队列
                Executors.defaultThreadFactory(),//线程工厂,一般是默认的
                new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,尝试去和最早的竞争,也不会抛出异常!
        try {
     
            //最大承载:Queue + max
            //超过了
            for (int i = 1; i <= 10; i++) {
     
                threadPool.execute(()->{
     
                    System.out.println(Thread.currentThread().getName()+"  OK");
                });
            }
        } catch (Exception e) {
     
            e.printStackTrace();
        }finally {
     
            //线程池用完,程序结束,关闭线程池
            threadPool.shutdown();
        }

    }
}

4种拒绝策略

10.彻底搞懂Java线程池_第3张图片

s

/**
 * 拒绝策略
 *  1.new ThreadPoolExecutor.AbortPolicy());//拒绝策略银行满了,还有人进来,不处理这个人,抛出异常
 *  2.new ThreadPoolExecutor.CallerRunsPolicy());//哪来的去哪里!队列满了,新来的人(线程)交给main线程执行
 *  3.new ThreadPoolExecutor.DiscardPolicy());//队列满了,丢掉任务,不会抛出异常
 *  4. new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,尝试去和最早的竞争,也不会抛出异常!
 */

小结和拓展

最大的线程如何设置!

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

知道了如何自定义线程池,那么该如何设置最大线程池大小呢?

//1.CPU 密集型 几核CPU就是几,可以保持CPU效率最高

//2.IO 密集型 >判断程序中十分耗IO的线程,如果程序 有15个大型任务 io十分占用资源。那么设置为2倍,30

ExecutorService threadPool = new ThreadPoolExecutor(
                2,//核心线程池大小
                Runtime.getRuntime().availableProcessors(),//最大线程池大小 根据CPU密集型来设置!!!!!
                3,//超时时间,超过后释放线程
                TimeUnit.SECONDS,//超时单位
                new LinkedBlockingQueue<>(3),//阻塞队列
                Executors.defaultThreadFactory(),//线程工厂,一般是默认的
                new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,尝试去和最早的竞争,也不会抛出异常!
            new LinkedBlockingQueue<>(3),//阻塞队列
            Executors.defaultThreadFactory(),//线程工厂,一般是默认的
            new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,尝试去和最早的竞争,也不会抛出异常!

你可能感兴趣的:(JUC并发编程,java,并发编程,一篇文章彻底搞懂Java线程池,多线程,队列)