欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java线程池的使用

程序员文章站 2024-03-02 14:58:58
...

最近Team在整理Code Review的一些Alignment。也看了下《阿里巴巴Java开发手册》,其中提到了线程和线程池的使用。这里简单整理下,可能没有条理。值得说一下,阿里也给出了一个在线编码规范的在线认证,有兴趣的可以试下。

代码规范

《阿里巴巴Java开发手册》在《并发处理》部分,有这样两条涉及线程池:

3.[强制]线程资源必须通过线程池提供,不允许在应用中自行显示创建线程。
说明:使用线程池的好处是减少在创建和线程上所花的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。
4.[强制]线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors返回的线程池对象的弊端如下:
1)FixedThreadPool和SingleThread:
允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
2)CachedThreadPool和ScheduledThreadPool:

允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。

线程池

我们知道创建线程有三种方式:Thread、Runnable和线程池。前两者使用起来相对简单,而线程池在一个系统内部使用时就需要加倍小心了。

创建

先看下线程池中最核心的一个类:java.uitl.concurrent.ThreadPoolExecutor。该类是深入了解Java中的线程池的关键。下边是它提供的四个可用构造函数。

public class ThreadPoolExecutor extends AbstractExecutorService {
	// ...
	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) {}
}

配置

上边构造函数用到的一些参数都是为线程池配置的参数:

corePoolSize:核心池的大小。默认情况下,当任务到来才创建线程并去执行任务。之后如果程池中的线程数达到corePoolSize,就把后续到达的任务放到缓存队列当。
maximumPoolSize:线程池最大线程数。表示在线程池中最多能创建多少个线程。避免创建过多的线程。
keepAliveTime:线程没有任务执行时最多保持多久时间会终止。
unit:参数keepAliveTime的时间单位。枚举类TimeUnit中给了7中可取值:天、小时、分钟、秒、毫秒、微妙、纳秒。
workQueue:一个阻塞队列,存储等待执行的任务。
threadFactory:线程工厂,用来创建线程。
handler:当拒绝处理任务时的处理程序。池中的数量和队列长度达到最大时,线程池就会拒绝新任务。ThreadPoolExecutor提供了四个静态内部类可供选择使用。

线程

先说下线程的状态。在Java中,线程的状态只能是下边五中状态中的一种。这点跟操作系统的线程状态有点不一样。

新建(New):创建后尚未启动的线程处于这种状态。(未调用start方法)
运行(Runable):包括操作系统线程状态中的Running和Ready。也就是说,该状态下,该线程有可能正在执行,也有可能等待CPU的时间片。
无限期等待(Waiting):该状态下,线程不会被分配CPU时间片。等待被其他线程显式地唤醒。
限期等待(Time Waiting):该状态下,线程也不会被分配CPU时间片。跟无限期等待不一样的是,在一定时间之后,它们会由系统自动唤醒,无须等待其他线程显式唤醒。
阻塞(Blocked):线程被阻塞了。等待获取一个排他锁,即由其他线程放弃锁时触发这个事件。
结束(Terminated):已终止线程的状态,即线程已经结束执行。

五种状态转换关系如下:

Java线程池的使用

类结构