码迷,mamicode.com
首页 > 编程语言 > 详细

线程池

时间:2020-02-17 14:17:36      阅读:52      评论:0      收藏:0      [点我收藏+]

标签:syn   核心   工作   token   元素   lex   获取   这一   href   

线程共包括以下 5 种状态:

1. 新建状态(New): 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。

2. 就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。

3. 运行状态(Running): 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。

4. 阻塞状态(Blocked): 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:

  • (01) 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。
  • (02) 同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
  • (03) 其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

5. 死亡状态(Dead): 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

为什么要使用线程池?

创建线程和销毁线程的花销是比较大的,这样频繁的创建线程和销毁线程,消耗系统资源的时间,可能导致系统资源不足。

线程池有什么作用?

1、提高效率 。
2、方便管理 。

比如说启动时有该程序创建100个线程,每当有请求的时候,就分配一个线程去工作,如果刚好并发有101个请求,那多出的这一个请求可以排队等候,避免因无休止的创建线程导致系统崩溃。

说说几种常见的线程池及使用场景:

链接:https://www.jianshu.com/p/6c6f396fc88e            https://www.liangzl.com/get-article-detail-158620.html

在JDK5版本中增加了内置线程池实现ThreadPoolExecutor,同时提供了Executors来创建不同类型的线程池。Executors中提供了以下常见的线程池创建方法:

  • 1、newSingleThreadExecutor:   创建一个单线程的线程池。如果因异常结束,会再创建一个新的,保证按照提交顺序执行。
  • 2、newFixedThreadPool:  创建固定大小的线程池。根据提交的任务逐个增加线程,直到最大值保持不变。如果因异常结束,会新创建一个线程补充。
  • 3、newCachedThreadPool:  创建一个可缓存的线程池。会根据任务自动新增或回收线程。
  • 4、newScheduledThreadPool:   支持定时以及周期性执行任务的需求。
  • 5、newWorkStealingPool:          JDK8新增,根据所需的并行层次来动态创建和关闭线程,通过使用多个队列减少竞争,底层使用ForkJoinPool来实现。优势在于可以充分利用多CPU,把一个任务拆分成多个“小任务”,放到多个处理器核心上并行执行;当多个“小任务”执行完成之后,再将这些执行结果合并起来即可。
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors各个方法的弊端:
1)newFixedThreadPool和newSingleThreadExecutor:
  主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
2)newCachedThreadPool和newScheduledThreadPool:
  主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。
 
使用场景:个人在项目中用到的是第三种,业务需求,每天会有调度服务器会通过http协议请求。
     定时调度,可能有多个http请求,把请求都放在controlerThreadPool里面。

线程池都有哪几种工作队列

1、ArrayBlockingQueue  :是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
2、LinkedBlockingQueue一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法                     Executors.newFixedThreadPool()使用了这个队列
3、SynchronousQueue一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
4、PriorityBlockingQueue一个具有优先级的无限阻塞队列

execute与submit的区别:

执行任务除了可以使用execute方法还可以使用submit方法。它们的主要区别是:execute适用于不需要关注返回值的场景,submit方法适用于需要关注返回值的场景。

核心参数作用解析如下:

  • corePoolSize:线程池核心线程数最大值。
  • maximumPoolSize:线程池最大线程数大小。
  • keepAliveTime:线程池中非核心线程空闲的存活时间大小。
  • unit:线程空闲存活时间单位。
  • workQueue:存放任务的阻塞队列。
  • threadFactory:创建新线程的工厂,所有线程都是通过该工厂创建的,有默认实现。
  • handler:线程池的拒绝策略。

程池的拒绝策略

构造方法的中最后的参数RejectedExecutionHandler用于指定线程池的拒绝策略。当请求任务不断的过来,而系统此时又处理不过来的时候,我们就需要采取对应的策略是拒绝服务。

默认有四种类型:

  • AbortPolicy策略:  该策略会直接抛出异常,阻止系统正常工作。
  • CallerRunsPolicy策略:  该策略只要线程池未关闭,该策略直接在调用者线程中,运行当前的被丢弃的任务。
  • DiscardPolicy策略:   该策略默默的丢弃无法处理的任务,不予任何处理。
  • DiscardOleddestPolicy策略: 该策略将丢弃最老的一个请求,也就是即将被执行的任务,并尝试再次提交当前任务。

当然,除了默认的4种策略之外,还可以根据业务需求自定义拒绝策略。通过实现RejectedExecutionHandler接口,在创建ThreadPoolExecutor对象时作为参数传入即可。

关闭线程池

关闭线程池可以调用shutdownNow和shutdown两个方法来实现。

shutdownNow:对正在执行的任务全部发出interrupt(),停止执行,对还未开始执行的任务全部取消,并且返回还没开始的任务列表。

shutdown:当我们调用shutdown后,线程池将不再接受新的任务,但也不会去强制终止已经提交或者正在执行中的任务。


  







线程池

标签:syn   核心   工作   token   元素   lex   获取   这一   href   

原文地址:https://www.cnblogs.com/lgg20/p/12321304.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!