在前面几篇博客中大体讲述了线程的大体思想和面对一些特殊多线程的处理现在出现了新的问题,当我想要处理线程问题的时候,我不可能一直处于创建和维持线程的存在,那么这个时候需要做的是想要创建一个新的东西,在里面存在很多或者足够使用的线程,当我需要在处理需要开辟一个新线程问题的时候,我可以在这个地方进行获得线程来处理这个事情,而在处理结束之后可以将线程从新放回线程之前所在的位置。为了达到这个目的,前人创建了一个新的概念叫做线程池。
做一个简单的比喻,生,官方说法线程作为进程执行的最小单位。线程池字面上理解就是一堆线程放在一起。打个比方,线程相当于小工,线程池相当于工程队。以前做任务A,招个小工过来,做任务B,招一个小工过来。。。。,这样的话就会出现一个问题,我招小工需要耗费时间精力,如果任务比较小,一会就做完了,那我费半天劲招个小工的时间都比干活的时间长,那我不是亏大了。因此,为了解决我频繁招工的问题,就需要建立一个工程队,这样就有了线程池的概念。有了工程队,现在工作的方式就变了,任务A来了,我招了小工甲,任务B来了,我招了小工乙,后面又来了任务C,小工甲刚好干完了,我直接就分配给小工甲,这次我就不用招工了。如果所有任务都做完了,我直接就解散工程队。大体就是这个样子的处理
那么做一个总结,作为一个线程池,我想要实现或者我需要为其完成那些内容
第一,类比上面的例子,我需要将其中的元素进行“付费”操作,即给予其一定的资源
第二,我需要为其负责,将其中的线程数量扩大到一个尽量不需要再二次扩大的程度
第三,在实现这个线程池的时候,应当提升工作效率
第四,可以的话,应该对这些线程进行管理,避免出现线程出现错误计算的情况
那么怎么创建一个线程池
并不需要自己对这个进行过多的处理,可以直接对其进行创建
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(new Runnable(){});
但Executors类在i作为线程池的工具大类,其中当然不会只存在一个对线程池处理的工具在处理线程池的时候只存在一种方法,查看Eecutors的源码可以得到以下的几种对线程池的处理
newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务
那么现在用官方的语言来解释什么是线程池
-其实就是一个 容纳多个线程的容器 ,其中的线程可以反复使用,省去了频繁创建线程对象的操作 ,--无需反复创建线程而消耗过多资源。
在这里切记一个原则
线程是系统独立调度和分派的基本单位,进程则是计算机在系统进行资源分配和调度的基本单位
相似于线程池,我们就可以扩展出来很多的其他池,比如说内存池,数据库池等,重要的不是池子的名字,而是其中相互连通的思想。