目录
线程池
1.1 什么是线程池
线程池是一种多线程处理形式。处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但要等到其他线程完成后才启动。
1.2 为什么需要线程池
有两种常见的创建线程的方法,一种是继承Thread类,一种是实现Runnable接口,Thread类其实也是实现了Runnable接口。但是我们创建这两种线程在运行结束后都会被虚拟机销毁,如果线程数量多的话,频繁地创建和销毁线程会大大浪费时间和效率,更重要的是浪费内存。
而线程池能很好地解决线程的重复利用,避免重复开销。
线程池的优点:
1、 重用存在的线程,减少对象创建销毁的开销
2、可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞
3、提供定时执行、定期执行、单线程、并发数控制等功能
1.3 Java提供的线程池
1.3.1 四种线程池
1、FixedThreadPool:该方法返回一个固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
2、SingleThreadExecutor:方法返回只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。
3、CachedThreadPool:该方法返回一个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复用。
4、ScheduledThreadPoolExecutor:主要用来给定的延迟后运行任务,或者定期执行任务。
1.3.2 使用场景
1、FixedThreadPool:适用于为了满足资源管理要求,而需要限制当前线程数量的应用场景。适用于负载比较重的服务器。
2、SingleThreadExecutor:适用于需要保证顺序地执行各个任务并且在任意时间点,不会有多个线程是活动的应用场景。
3、CachedThreadPool:适用于执行很多的短期异步任务的小程序,或者负载较轻的服务器。
4、ScheduledThreadPoolExecutor:适用于需要多个后台执行周期任务,同时为了满足资源管理需求而需要限制后台线程数量的应用场景。
5、SingleThreadScheduledExecutor:适用于需要单个后台执行周期任务,同时保证顺序地执行各个任务的应用场景。
1.4 创建线程池的方式
1、使用Executors创建
使用Executors工具类可以轻松创建。但我们一般不使用Executors去创建,而是通过ThreadPoolExecutor构造函数的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
2、ThreadPoolExecutor的构造函数创建
在创建的同时,给BlockQueue指定容量即可。
这种情况下,一旦提交的线程数超过当前可用线程数时,就会抛出java.util.concurrent.RejectedExecutionException,这是因为当前线程池使用的队列是有边界队列,队列已经满了便无法继续处理新的请求。但是异常(Exception)总比发生错误(Error)要好。
3、使用开源类库