Java线程池的使用学习

=Start=

缘由:

在之前记录的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:
如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。

为了应对这种情况,所以学习一下Java中线程池的使用,方便以后参考、查阅。

正文:

参考解答:
一、使用线程池(相较于new Thread的方式来说)的好处:
  • 降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 提高响应速度:当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  • 提高线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控。
二、线程池的实现原理

当一个新任务提交到线程池时,简单来说线程池的处理流程如下:

  1. 判断核心线程池里的线程是否都在执行任务,如果不是则创建一个新的工作线程处理任务,否则进入下个流程;
  2. 判断工作队列是否已满,如果未满则将新提交的任务存储在该工作队列,否则进入下个流程;
  3. 判断线程池里的线程是否都处于工作状态,如果不是则创建一个新的工作线程来执行任务,否则交由饱和策略处理。
三、Java中的ThreadPoolExecutor类

具体细节还是看下面的「参考链接」中的介绍吧,更深入详细。

四、使用示例

&

从上面这段代码的执行结果中可以看出,当线程池中线程的数目大于5时,便将任务放入任务缓存队列里面,当任务缓存队列满了之后,便创建新的线程。如果上面程序中,将for循环中改成执行20个任务,就会抛出任务拒绝异常了。


不过在Java doc中,并不提倡我们直接使用ThreadPoolExecutor,而是使用Executors类中提供的几个静态方法来创建线程池:

从它们的具体实现来看,它们实际上也是调用了ThreadPoolExecutor,只不过参数都已配置好了。

  • newFixedThreadPool创建的线程池corePoolSize和maximumPoolSize值是相等的,它使用的LinkedBlockingQueue;
  • newSingleThreadExecutor将corePoolSize和maximumPoolSize都设置为1,也使用的LinkedBlockingQueue;
  • newCachedThreadPool将corePoolSize设置为0,将maximumPoolSize设置为Integer.MAX_VALUE,使用的SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60秒,就销毁线程。

实际中,如果Executors提供的三个静态方法能满足要求,就尽量使用它提供的三个方法,因为自己去手动配置ThreadPoolExecutor的参数有点麻烦,要根据实际任务的类型和数量来进行配置。

另外,如果ThreadPoolExecutor达不到要求,可以自己继承ThreadPoolExecutor类进行重写。

参考链接:

=END=

声明: 除非注明,ixyzero.com文章均为原创,转载请以链接形式标明本文地址,谢谢!
https://ixyzero.com/blog/archives/3970.html

《Java线程池的使用学习》上有4条评论

  1. 高并发编程必备基础(上)
    https://mp.weixin.qq.com/s/ilXBIAHrHn1EWDlwWIJ5FQ

    借用Java并发编程实践中的话"编写正确的程序并不容易,而编写正常的并发程序就更难了",相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作的顺序是不可预期的,本文算是对多线程情况下同步策略的一个一个简单介绍。

    二、 什么是线程安全问题
    线程安全问题是指当多个线程同时读写一个状态变量,并且没有任何同步措施时候,导致脏数据或者其他不可预见的结果的问题。Java中首要的同步策略是使用Synchronized关键字,它提供了可重入的独占锁。

    三、 什么是共享变量可见性问题
    四、 原子性
    五、 CAS介绍
    六、 什么是可重入锁
    七、 Synchronized关键字
    八、 ReentrantReadWriteLock介绍
    九、 Volatile变量

hi进行回复 取消回复

电子邮件地址不会被公开。 必填项已用*标注