java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java线程池

深入了解Java线程池的原理使用及性能优化

作者:彷徨的蜗牛

JAVA线程池是一种管理和复用线程资源的机制,可以提高程序的效率和响应速度。本文将介绍线程池的原理、使用方法和性能优化技巧,帮助读者深入了解和应用JAVA线程池

1、什么是线程及线程池

线程是操作系统进行时序调度的基本单元。

线程池可以理解为一个存在线程的池子,就是一个容器,这个容器只能存在线程。这个容器有大小,可以放7,8个,也可以放3,4个。也可以把容器装满,但是都有一个最大值,比如说12个。比如说我这边线程池一般都装5个线程,最多能装12个。这个时候有五个人需要使用线程池,他就拿走了5个线程,然后在来两个人怎么办,他肯定没有线程可以使用,他必须等着那5个人使用完才行。但是我的池子能装12个,我只有5个线程怎么行,我肯定还得在在装几个线程,要不然人再多一点就不够了,这时候来了2个,我在生产2个线程,总数到7个,这个时候剩下2个人就不需要等待了,就可以直接使用。如果在来6个人呢,这个时候,我的池子里面可能只剩下5个线程的容量了,我能在生产5个线程但是,还有一个人得在哪等着才行。我也不能让人家漫无目的的等着啊,我找5个凳子吧,你们坐那等着,然后第一波五个人用完线程结束了,一下子腾出来了5个线程,剩下的一个人可以使用线程,这个时候依次又来了10个人,我的线程只有4个人可以使用,位置能坐五个人,剩下一个人怎么办,要不直接拒绝,我这边没有位,你要不先去别的地方看看,但是直接拒绝肯定很让人心里不舒服,我得在想几种拒绝策略。。。,我看我的线程池用的人还比较多,这么多人用,要是有人一直占着我的线程池怎么办,肯定得想个办法处理?要不就直接一个线程只能使用1分钟,使用完之后立刻回收,如果想在使用,重新排队等待。这样我的线程生意越做越好,只要有人用,他就一直跑。

是不是有点像饭店或者是自助餐店,自助餐店是比较形象的,我的饭店里面只要有位置就可以坐人,达到最大的量,剩下的客户只能在门口等待了,饭店里面的客户走一个,来一个在外边等待的,如果等待的位置没有了,客户看看没位置了就直接走了,如果有的人特别想吃,就在哪多等一会。在饭店里面的客户吃的时间也不能太长(一般在没有位置的情况下),大概2个小时,吃完就要离开。

根据以上我的描述,大概可以确定线程池里面有什么?

装了多少个线程、能装多少线程、线程可以保留多长时间、线程等待区、如何拒绝、创建线程

1.1、为什么要使用线程 

程序的运行必须依靠进程,进程的实际执行单元就是线程。

在很多程序中,需要多个线程互相同步或互斥的并行完成工作。

线程相比进程来说,更加的轻量,所以线程的创建和销毁的代价变得更小。

线程提高了性能,虽然线程宏观上是并行的,但微观上却是串行。从CPU角度线程并无法提升性能,但如果某些线程涉及到等待资源(比如IO,等待输入)时,多线程允许进程中的其它线程继续执行而不是整个进程被阻塞,因此提高了CPU的利用率,从这个角度会提升性能。

在多CPU或多核的情况下,使用线程不仅仅在宏观上并行,在微观上也是并行的。

1.2、为什么要使用线程池

多线程可以提高程序的执行性能

创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率(只要线程一直执行就不会销毁)

线程并发数量过多,抢占系统资源从而导致阻塞

对线程进行一些简单的管理

1.3、线程池的优点

提高线程利用率

提高程序的响应速度

便于统一管理线程对象

可以控制最大并发数

2、线程池在java中的使用

ThreadPoolExecutor这个类是java中的线程池类,可以使用它进行线程的池化。

// 根据上面的描述大概分析一下线程都需要什么及参数的解析
// corePoolSize 核心线程数,就是上面说的装了多少个线程
// maximumPoolSize 最大线程数,就是上面说的能装多少线程
// keepAliveTime 存活时间,就是上面说的线程可以保留多长时间
// TimeUnit 这个是时间单位,有时、分、秒、天等等,是存活时间的单位
// BlockingQueue<Runnable> 这是一个等待队列,就是上面显示的线程等待区
// ThreadFactory 线程工厂,就是上面描述的如何创建线程,由谁创建
// RejectedExecutionHandler 拒绝策略,就是上面显示的如何拒绝,是直接拒绝还是婉拒
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                          BlockingQueue<Runnable> workQueue)
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory)
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler)
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

可以看到,其需要如下几个参数:

2.1、线程池的工作原理

2.2、线程池的java代码示例

import java.util.concurrent.*;
public class ThreadTest {
    public static void main(String[] args) {
        ExecutorService threadPoolExecutor = new ThreadPoolExecutor(3, 5, 1L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory());
        for (int i = 0; i < 20; i++) {
            int finalI = i;
            threadPoolExecutor.submit( ()->{
                System.out.println(Thread.currentThread().getName() + "========" + finalI);
            });
        }
        threadPoolExecutor.shutdown();
    }
}

执行结果:

pool-1-thread-1========0
pool-1-thread-3========2
pool-1-thread-3========4
pool-1-thread-2========1
pool-1-thread-3========5
pool-1-thread-2========8
pool-1-thread-5========7
pool-1-thread-1========3
pool-1-thread-4========6
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@61e717c2 rejected from java.util.concurrent.ThreadPoolExecutor@66cd51c3[Running, pool size = 5, active threads = 2, queued tasks = 0, completed tasks = 7]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
at com.halo.communication.ThreadTest.main(ThreadTest.java:10)

执行的线程数超过了线程池可容纳的大小,线程池使用默认拒绝策略拒绝多余线程执行,然后开始出现异常处理。上面执行的线程数到thread-5,5是线程池的默认最大线程数。然后执行for循环20次,进行执行到8的时候出现异常,说明线程池已经超载满负荷执行,所以线程池执行拒绝策略。

到此这篇关于深入了解Java线程池的原理使用及性能优化的文章就介绍到这了,更多相关Java线程池内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文