Executor框架将任务实现与线程创建和执行任务的管理分离开来。 如果使用执行器,只需要实现Runnable对象,然后发送到执行器即可。管理线程是执行器的责任,当向执行器发送任务时,它尝试使用池线程来执行任务,以避免创建新线程。这种机制由Executor接口及其实现类作为ThreadPoolExecutor类提供。
本节将学习关于ThreadPoolExecutor执行器的状态信息,以及如何获取这些信息。
准备工作
本范例通过Eclipse开发工具实现。如果使用诸如NetBeans的开发工具,打开并创建一个新的Java项目。
实现过程
通过如下步骤实现范例:
-
创建名为Task的类,实现Runnable接口:
public class Task implements Runnable{
-
声明名为milliseconds的私有long属性:
private final long milliseconds;
-
实现类构造函数,初始化属性:
public Task (long milliseconds) { this.milliseconds=milliseconds; }
-
实现run()方法,设置线程休眠为milliseconds属性指定的毫秒数:
@Override public void run() { System.out.printf("%s: Begin\n", Thread.currentThread().getName()); try { TimeUnit.MILLISECONDS.sleep(milliseconds); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("%s: End\n", Thread.currentThread().getName()); } }
-
实现本范例主类,创建名为Main的类,包含main()方法:
public class Main { public static void main(String[] args) throws Exception{
-
使用Executors类的newCachedThreadPool()方法创建新的Executor对象:
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newCachedThreadPool();
-
创建和提交10个Task对象到执行器,使用随机数初始化这些对象:
Random random=new Random(); for (int i=0; i<10; i++) { Task task=new Task(random.nextInt(10000)); executor.submit(task); }
-
创建重复五次的循环,每次循环中,通过调用showLog()方法输出执行器信息到控制台,并设置线程休眠1秒钟:
for (int i=0; i<5; i++){ showLog(executor); TimeUnit.SECONDS.sleep(1); }
-
使用shutdown()方法关闭执行器:
executor.shutdown();
-
创建重复五次的循环,每次循环中,通过调用showLog()方法输出执行器信息到控制台,并设置线程休眠1秒钟:
for (int i=0; i<5; i++){ showLog(executor); TimeUnit.SECONDS.sleep(1); }
-
使用awaitTermination()方法等待执行器结束:
executor.awaitTermination(1, TimeUnit.DAYS);
-
输出指明程序结束的信息到控制台:
System.out.printf("Main: End of the program.\n"); }
-
实现showLog()方法,将Executor作为参数接收。输出池大小、任务数量和执行器状态信息到控制台:
private static void showLog(ThreadPoolExecutor executor) { System.out.printf("*********************"); System.out.printf("Main: Executor Log"); System.out.printf("Main: Executor: Core Pool Size: %d\n", executor.getCorePoolSize()); System.out.printf("Main: Executor: Pool Size: %d\n", executor.getPoolSize()); System.out.printf("Main: Executor: Active Count: %d\n", executor.getActiveCount()); System.out.printf("Main: Executor: Task Count: %d\n", executor.getTaskCount()); System.out.printf("Main: Executor: Completed Task Count: %d\n", executor.getCompletedTaskCount()); System.out.printf("Main: Executor: Shutdown: %s\n", executor.isShutdown()); System.out.printf("Main: Executor: Terminating: %s\n", executor.isTerminating()); System.out.printf("Main: Executor: Terminated: %s\n", executor.isTerminated()); System.out.printf("*********************\n"); } }
工作原理
本节,实现了阻塞执行线程随机毫秒数的任务。然后发送10个任务到执行器,且当等待任务结束时,输出执行器状态信息到控制台。使用如下方法得到Executor对象的状态:
- getCorePoolSize():返回整型数字,表示线程的核心数量。当执行器不执行任何任务时,它是在内部线程池中的最小线程数。
- getPoolSize():返回整型数字,表示内部线程池的实际大小。
- getActiveCount():返回整型数字,表示当前执行任务的线程数量。
- getTaskCount():返回长整型数字,表示计划执行的任务数量。
- getCompletedTaskCount():返回长整型数字,表示执行器已经执行且完成执行的任务数量。
- isShutdown():当调用执行器的shutdown()方法结束执行时,返回Boolean值。
- isTerminating():当执行器运行shutdown()操作但尚未结束时,返回Boolean值。
- isTerminated():当执行器结束执行时,返回Boolean值。
更多关注
- 第四章“线程执行器”中的“创建线程执行器并控制其被拒任务”小节
- 第八章“定制并发类”中的“定制ThreadPoolExecutor类”和“实现基于优先级的执行器类”小节