线程池是什么
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。
简单来说:创建一个线程池,其中有一定数量的线程,其中的线程任务结束后并不会立刻死亡,而是回到线程池中成为空闲状态,等待下一次调用。
但线程池中线程数量是一定的,不能过分的多,不然极易出现内存溢出
为什么使用线程池
我们有两种常见的创建线程的方法,一种是继承Thread类,一种是实现Runnable的接口,Thread类其实也是实现了Runnable接口。但是我们创建这两种线程在运行结束后都会被虚拟机销毁,如果线程数量多的话,频繁的创建和销毁线程会大大浪费时间和效率,更重要的是浪费内存,因为正常来说线程执行完毕后死亡,线程对象变成垃圾!那么有没有一种方法能让线程运行完后不立即销毁,而是让线程重复使用,继续执行其他的任务哪?我们使用线程池就能很好地解决这个问题。
怎么使用
从JDK5开始新增了一个Executors工厂类,通过该工厂类可以实现线程池,该类有如下几种常用方法:
-
public static ExecutorService newCachedThreadPool():创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程将会被缓存在线程池中;
-
public static ExecutorService newFixedThreadPool(int nThreads):创建一个可重用的、具有固定线程数的线程池;
-
public static ExecutorService newSingleThreadExecutor():创建一个只有单线程的线程池,相当于调用newFixedThreadPool(int nThreads)方法时传入参数为1。
-
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize):创建具有指定线程数的线程池,它可以在指定延迟后执行线程任务。 corePoolSize指池中所保存的线程数,即使线程时空闲的也被保存在线程池内。
-
public static ScheduledExecutorService newSingleThreadScheduledExecutor():创建只有一个线程的线程池,它可以在指定延迟后执行线程任务。
-
public static ExecutorService newWorkStealingPool(int parallelism):创建持有足够的线程的线程池来支持给定的并行级别,该方法还会使用多个队列来减少竞争。
-
public static ExecutorService newWorkStealingPool():该方法是前一个方法的简化版本。如果当前机器有4个CPU,则目标并行级别被设置为4,也就是相当于为前一个方法传入4作为参数。
我们最常用的为加粗的那个方法
ExecutionService表示一个线程池,该接口常用方法有:
- Future<?> submit(Runnable task)
- void shutdown()
下面示例:
class CountThread implements Runnable{
@Override
public void run(){
for(int i = 0; i < 10; i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class Test{
public static void main(String[] args){
//创建线程池对象,该线程池中有两个闲置线程
ExecutorService pool = Executors.newFixedThreadPool(2);
System.out.println(pool);
//创建并提交Runnable接口实现类实例
pool.submit(new CountThread());
pool.submit(new CountThread());
pool.submit(new CountThread());
//关闭线程池
pool.shutdown();
}
}
控制台输出如下:
可以得出pool对象 是实现ExecutorService接口的AbstractExecutorService的子类ThreadPoolExecutor的对象
同时也可以得出,当需要执行三个线程时,有一个只能等前两个使用完毕之后,再使用被使用完毕的空闲线程