线程池
Posted 空城余梦love
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程池相关的知识,希望对你有一定的参考价值。
我们之前使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。
假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。
如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。
java类库中提供的线程池简介:
java.util.concurrent包提供了现成的线程池的实现。
Executor是一个顶层接口,在它里面只声明了一个方法execute(Runnable),返回值为void,参数为Runnable类型,从字面意思可以理解,就是用来执行传进去的任务的;
然后ExecutorService接口继承了Executor接口,并声明了一些方法:submit、invokeAll、invokeAny以及shutDown等;
抽象类AbstractExecutorService实现了ExecutorService接口,基本实现了ExecutorService中声明的所有方法;
然后ThreadPoolExecutor继承了类AbstractExecutorService。
在ThreadPoolExecutor类中有几个非常重要的方法:
execute()
submit()
shutdown()
shutdownNow()
execute()方法实际上是Executor中声明的方法,在ThreadPoolExecutor进行了具体的实现,这个方法是ThreadPoolExecutor的核心方法,通过这个方法可以向线程池提交一个任务,交由线程池去执行。
submit()方法是在ExecutorService中声明的方法,在AbstractExecutorService就已经有了具体的实现,在ThreadPoolExecutor中并没有对其进行重写,这个方法也是用来向线程池提交任务的,但是它和execute()方法不同,它能够返回任务执行的结果,去看submit()方法的实现,会发现它实际上还是调用的execute()方法,只不过它利用了Future来获取任务执行结果
shutdown()和shutdownNow()是用来关闭线程池的。
不过在java doc中,并不提倡我们直接使用ThreadPoolExecutor,而是使用Executors类中提供的几个静态方法来创建线程池:
package pool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * newCachedThreadPool() * 线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。 * 有任务才会创建线程,空闲线程会被保留60s */ public class ThreadPoolExecutorTest1 { public static void main(String[] args) { ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int index = i; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } cachedThreadPool.execute(new Runnable() { @Override public void run() { System.out.println(index); System.out.println(Thread.currentThread().getName()); } }); } cachedThreadPool.shutdown();// 任务执行完毕,关闭线程池 } }
package pool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * newFixedThreadPool(int nThreads) * 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 * 线程池中包含固定数目的线程,空闲线程会一直保留,参数nThreads表示设定线程池中线程的数目 * */ public class ThreadPoolExecutorTest2 { public static void main(String[] args) { ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2); for (int i = 0; i < 10; i++) { final int index = i; fixedThreadPool.execute(new Runnable() { @Override public void run() { try { System.out.println(index); System.out.println(Thread.currentThread().getName()); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } fixedThreadPool.shutdown();// 任务执行完毕,关闭线程池 } }
package pool; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * newScheduledThreadPool(int corePoolSize) * 线程池能按时间计划来执行任务,允许用户设定计划执行任务的时间。 * 参数corePoolSize设定线程池中线程最小数目,当任务较多时,线程池可能会创建更多的工作线程来执行任务。 * */ public class ThreadPoolExecutorTest3 { public static void main(String[] args) { method1(); //method2(); } /** * 延迟3s执行 */ private static void method1(){ System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3); scheduledThreadPool.schedule(new Runnable() { public void run() { System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); System.out.println("延迟2s执行"); } }, 2, TimeUnit.SECONDS); scheduledThreadPool.shutdown(); } /** * 延迟2s执行后每3s执行一次 */ private static void method2() { System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3); scheduledThreadPool.scheduleAtFixedRate(new Runnable() { public void run() { System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); System.out.println("延迟2s执行后每3s执行一次"); System.out.println(Thread.currentThread().getName()); } }, 2, 3, TimeUnit.SECONDS); } }
package pool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * newSingleThreadExecutor(int nThreads) * 线程池中只有一个线程,它依次执行每个任务。 * 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。 * */ public class ThreadPoolExecutorTest4 { public static void main(String[] args) { ExecutorService singleThreadPool = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int index = i; singleThreadPool.execute(new Runnable() { @Override public void run() { try { System.out.println(index); System.out.println(Thread.currentThread().getName()); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } singleThreadPool.shutdown(); } }
package pool; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * newSingleThreadScheduledExecutor() * 线程池中只有一个线程,它能按照时间计划执行每个任务。 * */ public class ThreadPoolExecutorTest5 { public static void main(String[] args) { //method1(); method2(); } /** * 延迟3s执行 */ private static void method1(){ System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); ScheduledExecutorService scheduledThreadPool = Executors.newSingleThreadScheduledExecutor(); scheduledThreadPool.schedule(new Runnable() { public void run() { System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); System.out.println("延迟2s执行"); } }, 2, TimeUnit.SECONDS); } /** * 延迟2s执行后每3s执行一次 */ private static void method2() { System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); ScheduledExecutorService scheduledThreadPool = Executors.newSingleThreadScheduledExecutor(); scheduledThreadPool.scheduleAtFixedRate(new Runnable() { public void run() { System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); System.out.println("延迟2s执行后每3s执行一次"); System.out.println(Thread.currentThread().getName()); } }, 2, 3, TimeUnit.SECONDS); } }
转自:http://www.cnblogs.com/wbyp/p/7682680.html
以上是关于线程池的主要内容,如果未能解决你的问题,请参考以下文章