线程池引入
之前我们是需要一个线程就去创建一个线程,实现起来简单,但是当需要并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样由于频繁创建和销毁线程需要时间,就大大降低了系统的效率。
有没有一种办法可以使得线程复用,就是执行完一个任务,线程并不被销毁,而是可以继续执行其它任务呢?
有——线程池。
线程池里面的每一个线程代码结束后,线程并不会死亡,而是成为线程池中的空闲线程。
Executor、ExecutorService、Executors、ThreadPoolExecutor
Executor接口是一个顶层接口,在它里面只提供了一个方法:void execute(Runnable command)
command为可运行的任务,就是用来执行传进去的任务的。
ExecutorService接口继承了Executor接口,并声明了一些方法:submit、invokeAll、invokeAny以及shutDown等;
Executors类提供了几个重要的方法:
newCachedThreadPool()
newFixedThreadPoll()
newSingleThreadExecutor()
newCachedThreadPool方法构建了一个线程池。对于每个任务,如果有空闲线程可用,立即让它执行任务,如果没有可用的空闲线程,则创建一个新线程。newFixedThreadPoll方法构建一个具有固定大小的线程池。如果提交的任务数多于空闲的线程数,那么把得不到服务的任务放置到队列中。当其他任务完成再运行它们。newSingleThreadExecutor是一个退化了的大小为1的线程池:由1个线程执行提交的额任务,一个接一个。这3个方法返回了ExecutorService接口的ThreadPoolExecutor类的对象。
ThreadPoolExecutor类继承了类AbstractExecutorService,实现了Executor、ExecutorService 接口。在ThreadPoolExecutor类中有几个非常重要的方法:
excute()
submit()
shutdown()
shutdownnow()
getQueue() 、getPoolSize() 、getActiveCount()、getCompletedTaskCount()等获取与线程池相关属性的方法
excute() 实际上是Executor中声明的方法,在ThreadPoolExecutor进行了具体的实现,这个方法是ThreadPoolExecutor的核心方法,通过这个方法可以向线程池提交一个任务,交由线程池去执行。
submit()方法是在ExecutorService中声明的方法,在AbstractExecutorService就已经有了具体的实现,在ThreadPoolExecutor中并没有对其进行重写,这个方法也是用来向线程池提交任务的,但是它和execute()方法不同,它能够返回任务执行的结果,去看submit()方法的实现,会发现它实际上还是调用的execute()方法,只不过它利用了Future来获取任务执行结果。
shutdown()和shutdownNow()是用来关闭线程池的。调用了**shutdown()方法,则线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕。调用了shutdownNow()**方法,则线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务。
使用线程池
1.创建线程池对象:调用Excutors类中的静态方法newFixedThreadPool或者newCachedThreadPool方法;
2.给任务:调用submit方法提交任务(Runnable或Callable对象)
3.当不再提交任何任务时,调用shutdown。
使用Runnable还是Callable?
Callable是依赖于线程池存在的,不像Runnable可以依赖于线程(Thread类)和线程池,可见Callable的使用有一定局限性。Callable接口的call()方法有返回值,可以返回一个结果或抛出一个异常;Runnable接口的run()方法是void的,没有返回值。
代码:
//定义一个MyRunnable类实现Runnable接口
public class MyRunnable implements Runnable{
@Override
public void run() {
for(int x=0; x<100;x++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args){
//创建一个具有固定大小(6)的线程池
ExecutorService pool= Executors.newFixedThreadPool(6);
//提交任务 可以执行Runnable或者Callable对象代表的线程
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
//我不再提交任何任务了,所以结束线程池
pool.shutdown();
}
}