学会java这几个线程池的使用,会使得你的程序效率提升十倍

简介: 有时候在服务器处理客户端连接的时候,一个客户端我们都会创建一个线程去处理,但是我们可能会纳闷,难道有一万个客户端连接,我们也要创建一万个线程分别去处理嘛?这显然是不合理的。因此我们就用到了线程池这个概念。这篇文章就来好好的分析一下java中的四种线程池。

一、引言


1、new一个Thread的弊端


新建一个线程池其实是有很多弊端的,什么弊端呢?这里总结了三条。


(1) 每次new Thread新建对象性能差。因为每次都会创建一个对象。这是既耗时又消耗资源的。

(2) 线程缺乏统一管理,可能会造成自锁,或者是内存溢出。

(3)缺乏更多功能,如定时执行、定期执行、线程中断。


2、使用线程池的好处


相比new Thread,Java提供的四种线程池的好处在于:


(1)重用存在的线程,减少对象创建、消亡的开销,性能佳。

(2)可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。

(3)提供定时执行、定期执行、单线程、并发数控制等功能。


既然线程池这么好,我们就来看看如何使用吧。


二、线程池的使用


1、框架

v2-c061bff50db20b24c9049524228d7602_1440w.jpg

通过这张图我们可以看到,最下面的Excutors是整个线程池的核心。他里面提供了大量的创建线程池的方法。再往上走ThreadPoolExcutor就是一个线程池。在这个类里面定义了线程池的工作原理。


2、ThreadPoolExcutor


在这个类里面主要是通过这样一个方法参数来实现的线程池原理。

public ThreadPoolExecutor(
    int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    ThreadFactory threadFactory,
    RejectedExecutionHandler handler)

这里面的参数有必要好好地讲一下:


(1)int corePoolSize(核心线程数):

线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程,核心线程默认情况下会一直存活在线程池中;如果设置了 allowCoreThreadTimeOut 为 true,那么核心线程如果不干活的话,超过一定时间,就会被销毁掉。

(2)int maximumPoolSize(线程池能容纳的最大线程数量):

线程总数 = 核心线程数 + 非核心线程数。

(3)long keepAliveTime(非核心线程空闲存活时长):

非核心线程空闲时长超过该时长将会被回收

(4)TimeUnit unit 空闲线程的存活时间

在这里表示的是时间的单位,比如说秒。

(5)BlockingQueue workQueue(任务队列):

当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务。常用的workQueue类型:


①SynchornousQueue:这里表示接到新任务,直接交给线程处理,如果其他的线程都在工作,那就创建一个新的线程来处理这个任务。

②LinkedBlockingQueue:这里表示接到新任务,如果当前线程数小于核心线程数,则新建核心线程处理任务;如果当前线程数等于核心线程数,则进入队列等待。

③ArrayBlockingQueue:这里表示接到新任务,如果没有达到核心线程数,则新建核心线程执行任务,如果达到了,则入队等候,如果队列已满,则新建非核心线程执行任务,又如果总线程数到了 maximumPoolSize,并且队列也满了,则发生错误。

④DelayQueue:这里表示接到新任务,先入队,达到了指定的延时时间,才执行任务。


6.ThreadFactory threadFactory(线程工厂):

用来创建线程池中的线程。


7.RejectedExecutionHandler handler(拒绝策略):

指的之超过了maximumPoolSize,无法再处理新的任务,就会直接拒绝,提供了以下 4 种策略:


①AbortPolicy:默认策略,在拒绝任务时,会抛出RejectedExecutionException。

②CallerRunsPolicy:只要线程池未关闭,该策略直接在调用者线程中,运行当前的被丢弃的任务。

③DiscardOldestPolicy:该策略将丢弃最老的一个请求,也就是即将被执行的任务,并尝试再次提交当前任务。

④DiscardPolicy:该策略默默的丢弃无法处理的任务,不予任何处理。

v2-0416d591c616fbf8622741c2767a4f33_1440w.jpg

OK,有了这个最核心的线程池,我们就可以看看在这个ThreadPoolExcutor之上,Excutor为我们提供的几种线程池。


3、四种线程池


Executors提供的线程池配置方案


(1)构造一个固定线程数目的线程池,配置的corePoolSize与maximumPoolSize大小相同,同时使用了一个无界LinkedBlockingQueue存放阻塞任务,因此多余的任务将存在再阻塞队列,不会由RejectedExecutionHandler处理

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(
        nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>());
}

(2)构造一个缓冲功能的线程池,配置corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE,keepAliveTime=60s,以及一个无容量的阻塞队列 SynchronousQueue,因此任务提交之后,将会创建新的线程执行;线程空闲超过60s将会销毁

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(
        0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
         new SynchronousQueue<Runnable>());
}

(3)构造一个只支持一个线程的线程池,配置corePoolSize=maximumPoolSize=1,无界阻塞队列LinkedBlockingQueue;保证任务由一个线程串行执行

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService(
        new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>()));
}

(4)构造有定时功能的线程池,配置corePoolSize,无界延迟阻塞队列DelayedWorkQueue。

//第一种形式
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
//第二种形式
public static ScheduledExecutorService newScheduledThreadPool
    ( int corePoolSize, ThreadFactory threadFactory) {
    return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
//第三种
public ScheduledThreadPoolExecutor
    (int corePoolSize,ThreadFactory threadFactory) {
    super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
    new DelayedWorkQueue(), threadFactory);
}

其实对于线程池这块的知识点,真的是很多,这篇文章的出发点在于会根据自己的业务场景能够熟练的使用。希望对你有帮助

相关文章
|
1天前
|
安全 Java
【JAVA进阶篇教学】第十篇:Java中线程安全、锁讲解
【JAVA进阶篇教学】第十篇:Java中线程安全、锁讲解
|
1天前
|
安全 Java
【JAVA进阶篇教学】第六篇:Java线程中状态
【JAVA进阶篇教学】第六篇:Java线程中状态
|
1天前
|
缓存 Java
【JAVA进阶篇教学】第五篇:Java多线程编程
【JAVA进阶篇教学】第五篇:Java多线程编程
|
1天前
|
Java
【JAVA基础篇教学】第十二篇:Java中多线程编程
【JAVA基础篇教学】第十二篇:Java中多线程编程
|
1天前
|
安全 Java
java-多线程学习记录
java-多线程学习记录
|
1天前
|
数据采集 缓存 前端开发
LabVIEW用了多线程,程序是不是会跑的更快些
LabVIEW用了多线程,程序是不是会跑的更快些
|
2天前
|
Java Linux C语言
一步带你了解java程序逻辑控制
一步带你了解java程序逻辑控制
8 2
|
2天前
|
Java 数据安全/隐私保护
java中程序控制的典例
java中程序控制的典例
8 1
|
2天前
|
Java
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
10 0
|
2天前
|
设计模式 消息中间件 安全
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
9 0