程序启动一个新线程的成本是比较高的,因为涉及操作系统的交互.而使用线程池可以很好的提升性能
尤其在程序中要创建大量生存期很短的线程时,更应该考虑线程池的使用
创建线程池
在意识到需要使用线程池提升效率以后,如何创建线程池呢?
在JDK5版本,提供了一个Executors类来产生线程池,这是一个工厂类
Executors类的常用方法
创建线程池相关
1 2 3 4 5 6 7 8 9 10
| public static ExecutorService newCachedThreadPool()
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newSingleThreadExecutor()
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)
|
ExecutorService接口
这是一个线程池对象的接口,其中提供了线程池的操作方法
1 2 3 4 5 6 7
| Future<?> submit(Runnable task) <T> Future<T> submit(Runnable task, T result) <T> Future<T> submit(Callable<T> task) void shutdown() List<Runnable> shutdownNow() boolean isShutdown() boolean isTerminated()
|
submit相关
首先是测试使用newCachedThreadPool()创建线程池,测试默认线程池数量
从这里发现,线程池的默认名字和线程不同,默认从1开始
简单的案例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Runnable runnable1 = new Runnable() { @Override public void run() { for (int i =0;i<10;i++) { System.out.println(Thread.currentThread().getName() + " " + i); try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } } }; ExecutorService threadPool1 = Executors.newCachedThreadPool(); for (int i = 0;i<100000;i++) threadPool1.submit(runnable1);
|
结果很不理想,并未测试出默认线程池数量,因为再往上加估计要爆内存了
执行结果如下 :

终止执行的情况如下,电脑内存16G...10万都撑不住....

接下来是创建指定线程数量的线程池,修改代码如下 :
1 2 3 4
| ExecutorService threadPool2 = Executors.newFixedThreadPool(2); for (int i = 0; i<5;i++) threadPool2.submit(runnable1);
|
执行代码可以发现其只有两个线程,而且当所有线程全执行完以后程序也不会停止
执行结果如下 :

使用newSingleThreadExecutor()创建单个线程的线程池
执行结果如下 :

shutdown相关
我们对shutdown相关的方法进行测试
测试代码如下 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| Runnable runnable1 = new Runnable() { private String name = "拾荒者"; @Override public void run() { for (int i =0;i<3;i++) { System.out.println(this + " "+ name + i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); break; } } } @Override public String toString() {return Thread.currentThread().getName();} }; ExecutorService threadPool1 = Executors.newCachedThreadPool(); ExecutorService threadPool2 = Executors.newFixedThreadPool(2); for (int i = 0; i<5;i++) threadPool2.submit(runnable1); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } threadPool2.shutdown();
System.out.println(threadPool2.isShutdown()); System.out.println(threadPool2.isTerminated()); try {
Thread.sleep(1010); threadPool2.submit(runnable1); } catch (Exception e) { e.printStackTrace(); } System.out.println(threadPool2.isTerminated());
|
首先执行shutdown方法,可以发现
线程池会将之前提交的线程执行完毕
shutdown以后线程池就处于停止状态isShutdown()返回为true
isTerminated(结束)在线程运行完毕之前为false,运行完为true
停止之后不能在提交(执行)线程,否则抛RejectedExecutorException 拒绝执行异常
RejectedExecutorException属于运行时异常
执行结果如下 :

然后执行shutdownNow方法以及相关代码,可以发现
线程池在该方法执行时直接停止所有线程操作
故而抛出了两个InterruptException中断异常
且被直接停止的线程不会被返回
未执行的线程会被返回,以List集合形式
而isTerminated结束状态除了被停止的瞬间,其余时刻就为true
停止之后不能执行线程,一个道理
返回的未执行对象和原对象大致相同
返回的是FutureTask类型,可以继续运行这些未执行的线程
执行结果如下 :

