狂神说JAVA-JUC并发编程(五)线程池

程序运行的本质是占用系统资源,为了优化资源的使用,引入了池化技术
比如线程池、连接池。内存池、对象池
jdbc连接池会有一个最小的池(就是默认有几个连接的),有一个最大的池
因为连接跟关闭的时候是非常消耗资源的
池化技术:事先准备好一些资源,有人要用,就来拿,用完就归还

线程池的好处:降低资源消耗,提高响应速度,方便管理线程,线程可以复用,可以控制最大并发数

三大方法 7大参数 4种拒绝策略

在这里插入图片描述

三大方法

Executors.newSingleThreadExecutor()

package juc;

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

/**
 * Created by 此生辽阔 on 2021/6/27 9:32
 */
// Executors 工具类、3大方法
public class poolDemo {
    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();// 线程池用完,程序结束,关闭线程池
            //为了保证关闭线程池,把关闭的语句放在finally里面
        }

    }
}

在这里插入图片描述

Executors.newFixedThreadPool();

// 创建一个固定的线程池的大小

 ExecutorService threadPool = Executors.newFixedThreadPool(5); // 创建一个固定的线程池的大小

在这里插入图片描述

Executors.newCachedThreadPool()

根据cpu的性能,创建尽可能多的线程

 ExecutorService threadPool = Executors.newCachedThreadPool(); // 可伸缩的,遇强则强,遇弱则弱

在这里插入图片描述

7大参数

newSingleThreadExecutor()源码分析

 /**
     * Creates an Executor that uses a single worker thread operating
     * off an unbounded queue. (Note however that if this single
     * thread terminates due to a failure during execution prior to
     * shutdown, a new one will take its place if needed to execute
     * subsequent tasks.)  Tasks are guaranteed to execute
     * sequentially, and no more than one task will be active at any
     * given time. Unlike the otherwise equivalent
     * {@code newFixedThreadPool(1)} the returned executor is
     * guaranteed not to be reconfigurable to use additional threads.
     *
     * @return the newly created single-threaded Executor
     */
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

newFixedThreadPool()源码分析

 /**
     * Creates a thread pool that reuses a fixed number of threads
     * operating off a shared unbounded queue.  At any point, at most
     * {@code nThreads} threads will be active processing tasks.
     * If additional tasks are submitted when all threads are active,
     * they will wait in the queue until a thread is available.
     * If any thread terminates due to a failure during execution
     * prior to shutdown, a new one will take its place if needed to
     * execute subsequent tasks.  The threads in the pool will exist
     * until it is explicitly {@link ExecutorService#shutdown shutdown}.
     *
     * @param nThreads the number of threads in the pool
     * @return the newly created thread pool
     * @throws IllegalArgumentException if {@code nThreads <= 0}
     */
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

newCachedThreadPool()源码分析

 /**
     * Creates a thread pool that creates new threads as needed, but
     * will reuse previously constructed threads when they are
     * available.  These pools will typically improve the performance
     * of programs that execute many short-lived asynchronous tasks.
     * Calls to {@code execute} will reuse previously constructed
     * threads if available. If no existing thread is available, a new
     * thread will be created and added to the pool. Threads that have
     * not been used for sixty seconds are terminated and removed from
     * the cache. Thus, a pool that remains idle for long enough will
     * not consume any resources. Note that pools with similar
     * properties but different details (for example, timeout parameters)
     * may be created using {@link ThreadPoolExecutor} constructors.
     *
     * @return the newly created thread pool
     */
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

可以看到,三个方法的底层都是new ThreadPoolExecutor

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

我们点进去this

   /**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @param threadFactory the factory to use when the executor
     *        creates a new thread
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} or {@code handler} is null
     */
    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;
    }

在这里插入图片描述

这个时候我们再回到阿里巴巴开发手册

在这里插入图片描述

拒绝策略

如下图,银行柜台和候客区都满了,现在还有客户来,就只能拒绝了
在这里插入图片描述

手动创建一个线程池

模拟上面的银行业务
核心线程大小设为2:就是一直工作的窗口
最大线程设为5:就是银行最多的工作窗口
keepAliveTime设置为1小时:如果1小时都没有业务,就关闭窗口
候客区:new LinkedBlockingQueue(3),假设候客区最多3个人
线程工厂:就用默认的,Executors.defaultThreaFactory()
拒绝策略: 可以发现有4种拒绝策略,用默认的AbortPolicy()//银行满了,但是还有人进来,就不处理这个人,并抛出异常

在这里插入图片描述

工作中只会用 ThreadPoolExecutor,因为Executors不安全,阿里巴巴手册也说了

自定义线程池

package juc;

import javax.lang.model.element.VariableElement;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by 此生辽阔 on 2021/6/27 10:27
 */
public class poolDemo2 {
    public static void main(String[] args) {
        ThreadPoolExecutor threadPool= new ThreadPoolExecutor(2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

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

    }
}

当只有3个任务的时候,没有触发最大线程,即没有额外开银行窗口

在这里插入图片描述

增加到6个人的时候,触发了一个额外窗口

 for(int i=0;i<=5;i++)
            {
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" ok");
                });
            }

在这里插入图片描述

增加到8个人的时候,触发了全部窗口,即一共5个线程
在这里插入图片描述
增加到10个人就抛出异常了,超过了最大承载

 for(int i=0;i<=9;i++)
            {
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" ok");
                });
            }

在这里插入图片描述

现在改变拒绝策略
ThreadPoolExecutor.CallerRunsPolicy()

 ThreadPoolExecutor threadPool= new ThreadPoolExecutor(2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
               // new ThreadPoolExecutor.AbortPolicy());
                new ThreadPoolExecutor.CallerRunsPolicy());

可以看到,被拒绝的由主线程执行了
在这里插入图片描述

ThreadPoolExecutor.DiscardPolicy()
队列满了,不抛出异常,也不处理任务
可以看到,只处理了8个任务
在这里插入图片描述

ThreadPoolExecutor.DiscardOldestPolicy()
队列满了,就尝试和最早的任务竞争,如果竞争失败,这个任务就没了,也不会抛出异常,如果竞争成功,这个任务就可以执行

在这里插入图片描述

/**

  • new ThreadPoolExecutor.AbortPolicy() // 银行满了,还有人进来,不处理这个人的,抛出异
  • new ThreadPoolExecutor.CallerRunsPolicy() // 哪来的去哪里!
  • new ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常!
  • new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,尝试去和最早的竞争,也不会
    抛出异常!
    */

线程池的最大数量如何设定

 最大线程到底该如何定义
  1、CPU 密集型,几核,就是几,可以保持CPu的效率最高!(你的电脑是几个核心的(用程序获取),你的最大线程数就设置成几,可以保持CPu的效率最高)
  2、IO  密集型   > 判断你程序中十分耗IO的线程,
 程序   15个大型任务  io十分占用资源!(你的程序里面有15个任务很占用IO资源,就用15个线程去执行,所以最大
 线程数量大于这个15就好了,一般是大型IO任务数量的2倍)
package com.kuang.pool;

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

// Executors 工具类、3大方法

/**
 * new ThreadPoolExecutor.AbortPolicy() // 银行满了,还有人进来,不处理这个人的,抛出异常
 * new ThreadPoolExecutor.CallerRunsPolicy() // 哪来的去哪里!
 * 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值