java并发编程实战-线程池的使用2

时间:2022-03-24 18:03:40
1,线程池ThreadPoolExecutor
  1.1,如果某个线程的空闲时间超过了存或时间,那么将被标记为可回收的,并且当线程池的当前大小超过了基本大小时,这个线程将被终止
  1.2,通过调节线程池的基本大小和存或时间,可以帮助线程池回收空闲线程占有的资源。
  1.3,newFixedThreadPool工厂方法将线程池基本大小和最大大小设置为参数中的指定值,而且创建的线程池超时(默认使用*队列LinkedBlockingQueue)
  1.4,newCacheThreadPool工厂方法将线程池基本大小设置为0,最大大小设置为Integer.MAX_VALUE,超时设置为1分钟(默认使用同步移交机制SynchronousQueue)
  1.5,newSingleThreadPool工厂方法是个特例,它能确保不会有任务并发执行,因为它通过现场封闭来实现线程的安全性。(默认使用*队列LinkedBlockingQueue)
  1.6,ThreadPoolExecutor允许提供一个BlockingQueue来保存等待执行的任务。基本的任务排队方法有3中:*队列,有界队列和同步移交(Synchronous Handoff)
  1.7,比较稳妥的资源管理策略是使用有界队列,避免资源耗尽的情况发生。但同时带来一个问题:当队列填满后,新的任务该怎么处理?
  1.8,只有当任务相互独立时,为线程池或工作队列设置界限才是合理的。如果任务之间存在依赖性,那么有界的线程池或者队列可能导致线程的饥饿死锁问题,此时应该使用*的线程池。
2,饱和策略
  2.1,ThreadPoolExecutor的饱和策略可以通过调用setRejectedExecutionHandle来修改。
  2.2,JDK提供了几种不同的RejectExecutionHandle实现:AbortPolucy,CallerRunsPolicy,DiscardPolicy和DiscardOldestPolicy。
  2.3,默认的饱和策略是AbortPolicy,如果新任务无法提交到队列中等待执行,将被抛弃并抛出RejectExecutionException
  2.4,DiscardOldestPolicy会抛弃下一个将被执行的任务,如果等待队列时优先级队列,将抛弃优先级最高的任务。所有要慎用DiscardOldestPolicy和优先级队列放一起用
  2.5,CallerRunsPolicy既不会抛弃任务,也不会抛出异常,而是将任务会退给调用者执行。例如在webserver中采用此策略,当工作线程池满了后,下一个任务会由调用execute的主线程执行,这样主线程就没法再向线程池提交任务,再此期间主线程不会调用accept,因此请求被保存在TCP层的队列中而不是应用程序队列中。如果持续过载那么这种过载情况会逐渐向外蔓延开来。从线程池到工作队列到应用程序再到TCP层,最总到达客户端,导致服务器在高负载下实现一种平缓的性能降低。
3,线程工厂
  3.1,每当线程池需要创建线程时,都是通过线程工厂方法来完成,可以通过制定一个线程工厂的方法,来定制线程池的配置信息,如:给线程线程指定UncaughtExceptionHandle,给线程指定名字,打印特定线程日志或调试信息
  3.2,如果应用程序中需要利用安全策略来控制对某些特殊代码库的访问权限,可以通过Executors中的privilegeThreadFactory工厂来定制自己的线程工厂。如果不适用privilegeThreadFactory,线程池创建的线程将从调用execute或submit的客户端程序继承访问权限
  3.3,Executors中包含一个unconfigurableExecutorService工厂方法,该方法对一个现有的ExecutorService进行包装,使其只暴露ExecutorService的方法,因此不能对其进行参数配置了
4,ThreadPoolExecutor时可扩展的,它提供了几个可以在子类中改写的方法:beforeExecute,afterExecute和terminated