JAVA线程池Executor的简单使用

来源:互联网 发布:支付宝能解绑淘宝号码 编辑:程序博客网 时间:2024/05/18 02:58

         在JDK1.5之前,如果需要使用线程池,需要自己动手写代码实现,这对于初学者来说,不是一件容易的事。JDK1.5提供了Executor类,用户通过它可得到各种类型的线程池。

 

         Executor提供的线程池,可以分为:固定尺寸的线程池、可变尺寸的线程池。

 

 Executor.java提供部分接口

public static ExecutorService newFixedThreadPool(int nThreads)创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。public static ExecutorService newSingleThreadExecutor()创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。public static ExecutorService newCachedThreadPool()创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。public static ScheduledExecutorService newSingleThreadScheduledExecutor()创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。

 

       public static ExecutorService newFixedThreadPool(int n),线程池中有n个线程,如果实际线程数m,m>n,则先加入的前n个线程,先执行,处于执行状态,后加入的m-n个线程,处于阻塞状态,直到有某个线程执行完了,则处于阻塞状态的线程中的其中一个启动。也就是说最多同时n个线程处于执行状态。

package thread;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ThreadPoolTest {public static void main(String[] args) {ExecutorService executorService=Executors.newFixedThreadPool(3);MyThread a=new MyThread("A");MyThread b=new MyThread("B");MyThread c=new MyThread("C");MyThread d=new MyThread("D");executorService.execute(a);executorService.execute(b);executorService.execute(c);executorService.execute(d);executorService.shutdown();}static class MyThread implements Runnable{private String name;public MyThread(String name){this.name=name;}@Overridepublic void run(){for(int i=1;i<=5;i++){System.out.println(this.name+"第"+i+"次运行.........");try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}}}

运行结果


B第1次运行.........
C第1次运行.........
A第1次运行.........
B第2次运行.........
C第2次运行.........
A第2次运行.........
B第3次运行.........
C第3次运行.........
A第3次运行.........
B第4次运行.........
C第4次运行.........
A第4次运行.........
B第5次运行.........
C第5次运行.........
A第5次运行.........
D第1次运行.........
D第2次运行.........
D第3次运行.........
D第4次运行.........
D第5次运行.........

        ABC同时启动,所以打印顺序是混乱的;最后有空闲线程资源执行D时,只有它在执行,所以看上去有序。

 

       public static ExecutorService newSingleThreadExecutor()线程池中的线程数为1,如果实际线程数大于1时,则按照加入的顺序按顺序执行。所以如果开发中遇到多个线程一个个执行(前一个执行完后,后一个才能执行)的话,可以使用这种方式就可以避免使用join()方法,一个个控制了。

      将上面程序获得线程池的语句修改一下。

//ExecutorService executorService=Executors.newFixedThreadPool(3);ExecutorService executorService=Executors.newSingleThreadExecutor();


运行结果A第1次运行.........
A第2次运行.........
A第3次运行.........
A第4次运行.........
A第5次运行.........
B第1次运行.........
B第2次运行.........
B第3次运行.........
B第4次运行.........
B第5次运行.........
C第1次运行.........
C第2次运行.........
C第3次运行.........
C第4次运行.........
C第5次运行.........
D第1次运行.........
D第2次运行.........
D第3次运行.........
D第4次运行.........
D第5次运行.........

     运行结果是有序的。

     public static ExecutorService newCachedThreadPool()动态创建线程数,如果新加入一个线程任务,当前线程池中没有空闲的线程,则新创建一个线程用来执行新任务;如果有空闲线程,则使用空闲线程。一个线程的任务执行完后,线程状态成为空闲状态,线程不会立即销毁,60秒后,如果没有新任务进来,则空闲线程(空闲时间已达到60s)就销毁.

     将上面程序获取线程池的语句修改下。

//ExecutorService executorService=Executors.newFixedThreadPool(3);//ExecutorService executorService=Executors.newSingleThreadExecutor();ExecutorService executorService=Executors.newCachedThreadPool();


运行结果B第1次运行.........
D第1次运行.........
A第1次运行.........
C第1次运行.........
B第2次运行.........
D第2次运行.........
A第2次运行.........
C第2次运行.........
B第3次运行.........
D第3次运行.........
A第3次运行.........
C第3次运行.........
D第4次运行.........
B第4次运行.........
A第4次运行.........
C第4次运行.........
B第5次运行.........
D第5次运行.........
A第5次运行.........
C第5次运行.........

     ABCD的运行是混乱的。

 

       public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize),看方法名就知道,该线程池可以执行定时任务。

package thread;import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;public class ThreadPoolTest {public static void main(String[] args) {ScheduledExecutorService executorService=Executors.newScheduledThreadPool(3);MyThread a=new MyThread("A");MyThread b=new MyThread("B");MyThread c=new MyThread("C");MyThread d=new MyThread("D");executorService.schedule(a, 1000, TimeUnit.MILLISECONDS);//1000毫秒后执行executorService.schedule(b, 500, TimeUnit.MILLISECONDS);//500ms后执行executorService.schedule(c, 1, TimeUnit.SECONDS);//1s后执行executorService.schedule(d, 1, TimeUnit.SECONDS);executorService.shutdown();}static class MyThread implements Runnable{private String name;public MyThread(String name){this.name=name;}@Overridepublic void run(){for(int i=1;i<=3;i++)   System.out.println(name+"在执行第"+i+"次....."+new SimpleDateFormat("hh:mm:ss").format(new Date()));}}}

 

运行结果

B在执行第1次.....08:20:16
B在执行第2次.....08:20:16
B在执行第3次.....08:20:16
A在执行第1次.....08:20:17
A在执行第2次.....08:20:17
A在执行第3次.....08:20:17
C在执行第1次.....08:20:17
C在执行第2次.....08:20:17
C在执行第3次.....08:20:17
D在执行第1次.....08:20:17
D在执行第2次.....08:20:17
D在执行第3次.....08:20:17

         至于public static ScheduledExecutorService newSingleThreadScheduledExecutor(),读者可以将上面程序修改下就OK了。

运行结果

B在执行第1次.....08:25:08
B在执行第2次.....08:25:08
B在执行第3次.....08:25:08
A在执行第1次.....08:25:09
A在执行第2次.....08:25:09
A在执行第3次.....08:25:09
C在执行第1次.....08:25:09
C在执行第2次.....08:25:09
C在执行第3次.....08:25:09
D在执行第1次.....08:25:09
D在执行第2次.....08:25:09
D在执行第3次.....08:25:09