Java JUC线程池

简介: Java JUC 线程池



  1. 程池

程序的运行,本质上就是占用系统的资源,我们要做的就是优化资源的使用,所以衍生出一种技术叫:池化技术  线程池 连接池 内存池 对象池,都是类似的概念

什么是池化技术呢?

简单来说,池化技术就是:提前准备好一些资源,就来拿来使用,用完之后还回来,以供下次使用,这种思想可以是CPU效率更高

线程池的好处?

  1. 降低资源的消耗
  2. 提高响应的速度(不用频繁的创建销毁,使用完之后并不会进行销毁,而是返回到线程池,以便下次使用)
  3. 由于把线程都放在线程池中了,可以方便管理

总结来说:线程池的好处就是线程可以复用且方便管理,可以控制最大并发数

线程池该怎么使用呢?

  1. 创建线程池  

Executors.newxxx();

  1. 使用线程池创建线程

execute 使用线程池创建线程使用execute,丢弃之前的new Thread

  1. 关闭线程池 shutDown();

一般配合try catch finally使用 try中写创建线程池和业务,finally中关闭线程池


//创建线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();
//使用线程池创建线程
executorService.execute(()->{
            System.out.println(Thread.currentThread().getName() + "ok");
        });
//线程池使用完 使用shutDown()关闭线程池
    executorService.shutdown();
//创建一个单例线程
ExecutorService executorService = Executors.newSingleThreadExecutor();
//使用线程池创建线程的话 就不使用new Thread了  而且使用execute来创建线程
try {
for (int i = 0; i < 10; i++) {
        executorService.execute(()->{
            System.out.println(Thread.currentThread().getName() + "ok");
        });
    }
} catch (Exception e) {
    e.printStackTrace();
} finally {
  //线程池使用完 使用shutDown()关闭线程池
    executorService.shutdown();
}


简单来说就是:3大方法 7大参数 4种拒绝策略

线程池不允许使用Executors去创建(Executors其实就是个工具类,3大方法都和Executors有关),而是通过ThreadPoolExecutor的方式去创建,这样的处理方式可以更加明确线程池的运行规则,避免资源耗尽的风险(OOM内存溢出)

  3大方法

package com.wyh.ThreadPool;
import java.util.concurrent.Executors;
/**
 * @program: JUC
 * @description: 线程池
 * @author: 魏一鹤
 * @createDate: 2022-02-28 22:14
 **/
public class ThreadPoolDemo01 {
public static void main(String[] args){
        //Executors其实就是个工具类,3大方法都在它里面
        //3大方法 1 newSingleThreadExecutor得到一个单一的线程池 这个线程池只有一个线程处理
        Executors.newSingleThreadExecutor();
        //3大方法 2 newFixedThreadPool得到一个固定的线程池大小  参数就是线程池大小
        Executors.newFixedThreadPool(5);
        //3大方法 3 newFixedThreadPool得到一个缓存的线程池 可以伸缩的 遇强则强遇弱则弱
        Executors.newCachedThreadPool();
    }
}

1 单一的线程池


Executors.newSingleThreadExecutor();  //得到一个单一的线程池 这个线程池只有一个线程处理


package com.wyh.ThreadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * @program: JUC
 * @description: 线程池
 * @author: 魏一鹤
 * @createDate: 2022-02-28 22:14
 **/
public class ThreadPoolDemo01 {
public static void main(String[] args){
        //创建一个单例线程
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        //使用线程池创建线程的话 就不使用new Thread了  而且使用execute来创建线程
        try {
for (int i = 0; i < 10; i++) {
            //使用线程池创建线程的话 就不使用new Thread了  而且使用execute来创建线程
                executorService.execute(()->{
                    System.out.println(Thread.currentThread().getName() + "ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
  //线程池使用完 使用shutDown()关闭线程池
            executorService.shutdown();
        }
    }
}


通过结果发现线程池中的线程被一个线程调用 这就是单例线程池



pool-1-thread-1ok

pool-1-thread-1ok

pool-1-thread-1ok

pool-1-thread-1ok

pool-1-thread-1ok

pool-1-thread-1ok

pool-1-thread-1ok

pool-1-thread-1ok

pool-1-thread-1ok

pool-1-thread-1ok



2 固定的线程池


Executors.newFixedThreadPool(5);  //得到一个固定的线程池大小  参数就是线程池大小


package com.wyh.ThreadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * @program: JUC
 * @description: 线程池
 * @author: 魏一鹤
 * @createDate: 2022-02-28 22:14
 **/
public class ThreadPoolDemo01 {
public static void main(String[] args){
        //创建一个固定个数的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
//使用线程池创建线程的话 就不使用new Thread了  而且使用execute来创建线程
        try {
for (int i = 0; i < 10; i++) {
            //使用线程池创建线程的话 就不使用new Thread了  而且使用execute来创建线程
                executorService.execute(()->{
                    System.out.println(Thread.currentThread().getName() + "ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
//线程池使用完 使用shutDown()关闭线程池
            executorService.shutdown();
        }
    }
}


pool-1-thread-2ok

pool-1-thread-4ok

pool-1-thread-3ok

pool-1-thread-6ok

pool-1-thread-1ok

pool-1-thread-5ok

pool-1-thread-8ok

pool-1-thread-7ok

pool-1-thread-9ok

pool-1-thread-10ok



通过结果发现线程池中的线程被多个线程并发调用,最多的并发数是我创建线程池时生命的线程个数 这就是固定个数线程池

就算我用10个线程并发执行,但是创建线程池个数就是1,那这10个线程也是被这被一个线程并发执行,这个思想类似于单例线程池,不管并发量多少都是一个线程并发执行




package com.wyh.ThreadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * @program: JUC
 * @description: 线程池
 * @author: 魏一鹤
 * @createDate: 2022-02-28 22:14
 **/
public class ThreadPoolDemo01 {
public static void main(String[] args){
        ExecutorService executorService = Executors.newFixedThreadPool(1);
try {
for (int i = 0; i < 10; i++) {
//使用线程池创建线程的话 就不使用new Thread了  而且使用execute来创建线程
                executorService.execute(()->{
                    System.out.println(Thread.currentThread().getName() + "ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
//线程池使用完 使用shutDown()关闭线程池
            executorService.shutdown();
        }
    }
}

3 可缓存的线程池


Executors.newCachedThreadPool(); //得到一个缓存的线程池 可以伸缩的 遇强则强遇弱则弱


package com.wyh.ThreadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * @program: JUC
 * @description: 线程池
 * @author: 魏一鹤
 * @createDate: 2022-02-28 22:14
 **/
public class ThreadPoolDemo01 {
public static void main(String[] args){
            //创建一个可缓存的线程池 会随着线程个数提高并发量 遇强则强遇弱则弱,强弱根据线程数决定
        ExecutorService executorService = Executors.newCachedThreadPool();
try {
for (int i = 0; i < 50; i++) {
//使用线程池创建线程的话 就不使用new Thread了  而且使用execute来创建线程
                executorService.execute(()->{
                    System.out.println(Thread.currentThread().getName() + "ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
//线程池使用完 使用shutDown()关闭线程池
            executorService.shutdown();
        }
    }
}

通过结果发现线程池中的线程并发量会随着线程个数提高并发量 遇强则强遇弱则弱,强弱根据线程数决定,这就是缓存线程池


pool-1-thread-2ok

pool-1-thread-5ok

pool-1-thread-6ok

pool-1-thread-4ok

pool-1-thread-8ok

pool-1-thread-1ok

pool-1-thread-3ok

pool-1-thread-9ok

pool-1-thread-5ok

pool-1-thread-7ok

pool-1-thread-7ok

pool-1-thread-5ok

pool-1-thread-9ok

pool-1-thread-2ok

pool-1-thread-1ok

pool-1-thread-10ok

pool-1-thread-3ok

pool-1-thread-6ok

pool-1-thread-4ok

pool-1-thread-8ok

pool-1-thread-11ok

pool-1-thread-3ok

pool-1-thread-10ok

pool-1-thread-13ok

pool-1-thread-1ok

pool-1-thread-9ok

pool-1-thread-1ok

pool-1-thread-2ok

pool-1-thread-7ok

pool-1-thread-5ok

pool-1-thread-15ok

pool-1-thread-9ok

pool-1-thread-1ok

pool-1-thread-7ok

pool-1-thread-2ok

pool-1-thread-14ok

pool-1-thread-13ok

pool-1-thread-10ok

pool-1-thread-8ok

pool-1-thread-11ok

pool-1-thread-3ok

pool-1-thread-12ok

pool-1-thread-6ok

pool-1-thread-4ok

pool-1-thread-18ok

pool-1-thread-1ok

pool-1-thread-17ok

pool-1-thread-7ok

pool-1-thread-16ok

pool-1-thread-5ok


7大参数

无论是哪种线程池,本质都是调用ThreadPoolExecutor,它有7大参数

  1. corePoolSize    核心线程池大小
  2. maximumPoolSize  最大线程池大小
  3. long keepAliveTime  超时等待 (超时了没有还调用会释放)
  4. TimeUnit unit    超时时间单位
  5. BlockingQueue<Runnable> workQueue  阻塞队列
  6. ThreadFactory threadFactor 线程工厂 创建线程的 一般不用动
  7. RejectedExecutionHandler handler  拒绝策略


//本质 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;
}


自定义手动创建线程池


//使用ThreadPoolExecutor自定义线程池 它有7个参数
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,//核心线程池大小 正常只有2个线程处理
        5, //最大线程池大小  并发量大的时候最多处理的线程数
        3, //等待时间  3
        TimeUnit.SECONDS, //时间单位  秒
        new LinkedBlockingDeque<>(3),//阻塞队列  存放的队列数
        Executors.defaultThreadFactory(),//线程工程  Executors的defaultThreadFactory方法默认创建的线程工厂 一般不用变
        new ThreadPoolExecutor.AbortPolicy());//拒绝策略 如果队列满了 还有队列进来 就不处理满了之后进来的队列,并且抛出异常



4种拒绝策略

默认的拒绝策略:Abortpolicy 如果队列满了 还有队列进来 就不处理满了之后进来的队列,并且抛出异常


1 Abortpolicy   如果队列满了 还有队列进来 就不处理满了之后进来的队列,并且抛出异常


2   CallerRunsPolicy 哪来的去哪里(打发)



3 DiscardPolicy  队列满了,丢掉多余的任务 不会抛出异常



4  DiscardOldestPolicy 队列满了,会尝试和旧的队列(最早加入的队列)竞争 也不会抛出异常


总结和扩展:

创建线程池使用的是ThreadPoolExecutor而不是Executros,因为Executros不安全(max=Interger.max)相当于20亿个线程,会造成OOM(内存溢出)异常

知道线程池的3种线程池(3大方法),7大参数,4种拒绝策略

线程池的最大的大小应该如何定义设置?

一般有两种方法

IO密集型和CPU密集型一般用于调优(优化性能)

1 CPU密集型 几核,就把最大线程定义为几,可以保证CPU的效率最高

Runtime.getRuntime().availableProcessors() //获取cpu处理器个数 也叫CPU密集型
//使用ThreadPoolExecutor自定义线程池 它有7个参数
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,//核心线程池大小 正常只有2个线程处理
       //最大线程数一般写电脑的处理器个数 使用CPU密集型   Runtime.getRuntime().availableProcessors() 获取该电脑有多少cpu处理器
        Runtime.getRuntime().availableProcessors(), //最大线程池大小  并发量大的时候最多处理的线程数
        3, //等待时间  3
        TimeUnit.SECONDS, //时间单位  秒
        new LinkedBlockingDeque<>(3),//阻塞队列  存放的队列数
        Executors.defaultThreadFactory(),//线程工程  Executors的defaultThreadFactory方法默认创建的线程工厂 一般不用变
        //拒绝策略
        // 1 AbortPolicy  如果队列满了 还有队列进来 就不处理满了之后进来的队列,并且抛出异常
        //new ThreadPoolExecutor.AbortPolicy()
        // 2 CallerRunsPolicy 哪来的去哪里 new ThreadPoolExecutor.CallerRunsPolicy
        // 3 DiscardPolicy  队列满了,丢掉多余的任务 不会抛出异常   ThreadPoolExecutor.DiscardPolicy()
        // 4 DiscardOldestPolicy 队列满了,会尝试和旧的队列(最早加入的队列)竞争 也不会抛出异常  new ThreadPoolExecutor.DiscardOldestPolicy()
        new ThreadPoolExecutor.DiscardOldestPolicy());

2 IO密集型  判断程序中十分耗费IO的线程,然后定义的最大线程大于耗费IO的线程就可以了,一般定义的最大线程数是IO耗费的两倍

比如一个程序中有15个大型任务,IO任务非常占用资源,至少有15个线程去操作IO任务,那么线程池就可以定义30个最大线程,是IO线程的两倍

目录
相关文章
|
7天前
|
设计模式 缓存 安全
【JUC】(6)带你了解共享模型之 享元和不可变 模型并初步带你了解并发工具 线程池Pool,文章内还有饥饿问题、设计模式之工作线程的解决于实现
JUC专栏第六篇,本文带你了解两个共享模型:享元和不可变 模型,并初步带你了解并发工具 线程池Pool,文章中还有解决饥饿问题、设计模式之工作线程的实现
42 2
|
7天前
|
设计模式 消息中间件 安全
【JUC】(3)常见的设计模式概念分析与多把锁使用场景!!理解线程状态转换条件!带你深入JUC!!文章全程笔记干货!!
JUC专栏第三篇,带你继续深入JUC! 本篇文章涵盖内容:保护性暂停、生产者与消费者、Park&unPark、线程转换条件、多把锁情况分析、可重入锁、顺序控制 笔记共享!!文章全程干货!
48 1
|
7天前
|
Java 测试技术 API
【JUC】(1)带你重新认识进程与线程!!让你深层次了解线程运行的睡眠与打断!!
JUC是什么?你可以说它就是研究Java方面的并发过程。本篇是JUC专栏的第一章!带你了解并行与并发、线程与程序、线程的启动与休眠、打断和等待!全是干货!快快快!
173 2
|
7天前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
51 1
|
7天前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
42 1
|
8天前
|
缓存 安全 Java
JUC系列《深入浅出Java并发容器:CopyOnWriteArrayList全解析》
CopyOnWriteArrayList是Java中基于“写时复制”实现的线程安全List,读操作无锁、性能高,适合读多写少场景,如配置管理、事件监听器等,但频繁写入时因复制开销大需谨慎使用。
|
8天前
|
缓存 安全 Java
JUC系列之《CountDownLatch:同步多线程的精准发令枪 》
CountDownLatch是Java并发编程中用于线程协调的同步工具,通过计数器实现等待机制。主线程等待多个工作线程完成任务后再继续执行,适用于资源初始化、高并发模拟等场景,具有高效、灵活、线程安全的特点,是JUC包中实用的核心组件之一。
|
8天前
|
设计模式 算法 安全
JUC系列之《深入理解AQS:Java并发锁的基石与灵魂 》
本文深入解析Java并发核心组件AQS(AbstractQueuedSynchronizer),从其设计动机、核心思想到源码实现,系统阐述了AQS如何通过state状态、CLH队列和模板方法模式构建通用同步框架,并结合独占与共享模式分析典型应用,最后通过自定义锁的实战案例,帮助读者掌握其原理与最佳实践。
|
前端开发 Java C++
JUC系列之《CompletableFuture:Java异步编程的终极武器》
本文深入解析Java 8引入的CompletableFuture,对比传统Future的局限,详解其非阻塞回调、链式编排、多任务组合及异常处理等核心功能,结合实战示例展示异步编程的最佳实践,助你构建高效、响应式的Java应用。
|
29天前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案

热门文章

最新文章