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

时间:2021-11-13 17:59:53

1,在任务与执行策略之间的隐形耦合

  1.1,Executor框架可以将任务的提交与任务的执行策略解耦开来,并且为制定和修改执行策略都提供了相当大的灵活性,但并非所有的任务都能够使用所有的执行策略。有些类型任务需要明确地指定执行策略:依赖性任务,使用线程封闭机制的任务,对响应时间敏感的任务,使用ThreadLocal的任务。

  1.2,依赖于其他任务的任务,要求线程池足够大,从而确保他们依赖的任务不会被放入等待队列中或被拒绝。
  1.3,采用封闭机制的任务需要串行执行
  1.4,只有当线程本地值得生命周期受限于任务的生命周期时,线程池中的线程使用ThreadLocal才有意义,而线程池中的线程不应该使用ThreadLocal在任务之间传递值
  1.5,只有当任务都是同类型的并且相互独立时,线程池的性能才能达到最佳,如果将运行时间较长的和运行时间较短的任务混在一起,那么可能造成“拥塞”,如果提交的任务依赖于其他任务,那么可能造成死锁。
2,线程饥饿死锁
  2.1,在线程池中,如果任务依赖于其他任务,那么可能产生死锁。
  2.2,在单线程的Executor中,如果一个任务将另一个任务提交到同一个Executor,并且等待这个被提交任务的结果,那么通常会引发死锁。
  2.3,如果在更大的线程池中,所有的线程都由于在等待其他仍处于工作队里中的任务而阻塞,那么同样会发生死锁,这被称为线程饥饿死锁。
  2.4,只要线程池中的任务需要无限期地等待一些必须由池中其他任务才能提供的资源或条件,那么除非线程池足够大,否则将发生线程饥饿死锁
  2.5,如果任务阻塞时间过长,那么也会影响程序的响应性,因此平台类库的大多数可阻塞方法中,同时定义了限时版和无限时版本,例如Thread.join,BlockingQueue.put,CountDownLatch.await以及Selector.select等。
3,设置线程池的大小
  3.1,代码中通常不会固定线程池的大小,而应通过某种配置机制来提供,或者根据Runtime.availableProcessors来动态计算。
  3.2,在计算密集型的任务,在拥有N个处理器的系统上,当线程池大小为N+1时,通常能实现最优的利用率。
  3.3,如果线包含IO或者其他的阻塞操作,那么线程数应该设置大写
  3.4,线程池最优大小应为:N=(等待时间+执行时间)/执行时间*cpu个数*cpu使用率
  3.5,可以通过Runtime.getRuntime().availableProcessors();来获取CPU数目
  3.6,如果线程池大小依赖于一些其他资源,如内存、文件句柄、套接字句柄和数据库连接等,那么线程池大小的上限就是该资源可用总量除以每个人无需求量
  3.7,如果线程池依赖于其他资源池,那么线程池与资源池将会相互依赖