每一个线程的启动和结束都是比较消耗时间和占用资源的。
如果在系统中用到了很多的线程,大量的启动和结束动作会导致系统的性能变卡,响应变慢。
为了解决这个问题,引入线程池这种设计思想。
线程池的模式很像生产者消费者模式,消费的对象是一个一个的能够运行的任务。
线程池设计思路
线程池的思路和生产者消费者模型是很接近的。
1、准备一个任务容器
2、一次性启动10个消费者线程
3、刚开始任务容器时是空的,所以线程都wait在上面。
4、直到一个外部线程往这个任务容器中扔了一个”任务”,就会有一个消费者线程被唤醒notify
。
5、这个消费者线程取出”任务”,并且执行这个任务,执行完毕后,继续等待下一次任务的到来。
6、如果短时间内,有较多的任务加入,那么就会有多个线程别唤醒,去执行这些任务。
开发一个自定义的线程池
这是一个自定义的线程池,虽然不够完善和健壮,但是已经足以说明线程池的工作原理。
缓慢的给这个线程池添加任务,会看到有多条线程来执行这些任务。
线程7执行完毕任务后,又回到池子里,下一次任务来的时候,线程7又来执行新的任务。ThreadPool.java
TestThread.java
测试线程池
创造一个情景,每个任务执行的时间都是1秒。
刚开始是间隔1秒钟向线程池中添加任务,
然后间隔时间越来越短,执行任务的线程还没有来得及结束,新的任务又来了。
就会观察到线程池里的其他线程被唤醒来执行这些任务。TestThread.java
使用Java自带的线程池
Java提供自带的线程池,而不需要自己去开发一个自定义线程池。
线程池类ThreadPoolExecutor
在包java.util.concurrent
下
第一个参数10
表示这个线程池初始化了10
个线程在里面工作。核心线程数
第二个参数15
表示如果10个线程不够用了,就会自动增加到最多15个线程
。最大线程数
第三个参数60
结合第四个参数TimeUnit.SECONDS
,表示经过60秒
,多出来的线程还没有接到活儿,就会回收,最后保持池子里就10个。闲置线程存活时间
第四个参数TimeUnit.SECONDS
如上。时间单位
第五个参数new LinkedBlockingQueue()
用来放任务的集合。线程队列
execute
方法用于添加新的任务。
借助线程池同步查找文件内容
初始化一个大小是10的线程池
遍历所有文件,当遍历到文件是.java
的时候,创建一个查找文件的任务,把这个任务扔进线程池去执行,继续遍历下一个文件。SearchFileTask.java
ThreadPool.java
TestThread.java