Executor框架将任务实现与线程创建和执行任务的管理分离开来。Java提供的fork/join框架扩展了执行器框架,用于解决特定类型的问题,以提高其它解决方案(直接使用Thread对象或者执行器框架)的性能。
fork/join框架旨在解决使用fork()和join()操作能够分解为更小任务的问题。实现此特性的主类是ForkJoinPool。
本节将学习关于ForkJoinPool执行器的状态信息,以及如何获取这些信息。
准备工作
本范例通过Eclipse开发工具实现。如果使用诸如NetBeans的开发工具,打开并创建一个新的Java项目。
实现过程
通过如下步骤实现范例:
-
创建名为Task的类,继承RecursiveAction类:
public class Task extends RecursiveAction{
-
声明名为array的私有int数组属性,存储待增加的元素数组:
private final int array[];
-
声明名为start和end的两个私有int属性,存储需要处理的任务元素块的开始和结束位置:
private final int start; private final int end;
-
实现类构造函数,初始化属性:
public Task (int array[], int start, int end) { this.array=array; this.start=start; this.end=end; }
-
实现compute()方法,包含任务的主要逻辑。如果任务需要处理超过100个元素,首先将元素拆分成两部分,创建两个任务分别执行每部分,使用fork()方法开始执行任务,最后使用join()方法等待任务结束:
@Override protected void compute() { if (end-start>100) { int mid=(start+end)/2; Task task1=new Task(array,start,mid); Task task2=new Task(array,mid,end); task1.fork(); task2.fork(); task1.join(); task2.join();
-
否则,执行增加元素的操作,并在每次操作之后,设置线程休眠5毫秒:
} else { for (int i=start; i<end; i++) { array[i]++; try { Thread.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
-
实现本范例主类,创建名为Main的类,包含main()方法:
public class Main { public static void main(String[] args) throws Exception{
-
创建名为pool的ForkJoinPool对象:
ForkJoinPool pool=new ForkJoinPool();
-
创建名为array的整型数字数组,包含10000个元素:
int array[]=new int[10000];
-
创建新Task对象,处理整个数组:
Task task1=new Task(array,0,array.length);
-
使用execute()犯法发送执行任务到池中:
pool.execute(task1);
-
如果任务尚未执行结束,调用showLog()方法输出ForkJoinPool类状态信息到控制台,然后设置线程休眠1秒钟:
while (!task1.isDone()) { showLog(pool); TimeUnit.SECONDS.sleep(1); }
-
使用shutdown()方法关闭池:
pool.shutdown();
-
使用awaitTermination()等待池运行结束:
pool.awaitTermination(1, TimeUnit.DAYS);
-
调用showLog()方法输出ForkJoinPool类状态信息到控制台,然后输出指明程序结束的信息到控制台:
showLog(pool); System.out.printf("Main: End of the program.\n"); }
-
实现showLog()方法,将ForkJoinPool对象作为参数接收,输出其状态和线程,以及正在执行的任务信息到控制台:
private static void showLog(ForkJoinPool pool) { System.out.printf("**********************\n"); System.out.printf("Main: Fork/Join Pool log\n"); System.out.printf("Main: Fork/Join Pool: Parallelism: %d\n", pool.getParallelism()); System.out.printf("Main: Fork/Join Pool: Pool Size: %d\n", pool.getPoolSize()); System.out.printf("Main: Fork/Join Pool: Active Thread Count: %d\n", pool.getActiveThreadCount()); System.out.printf("Main: Fork/Join Pool: Running Thread Count: %d\n", pool.getRunningThreadCount()); System.out.printf("Main: Fork/Join Pool: Queued Submission: %d\n", pool.getQueuedSubmissionCount()); System.out.printf("Main: Fork/Join Pool: Queued Tasks: %d\n", pool.getQueuedTaskCount()); System.out.printf("Main: Fork/Join Pool: Queued Submissions: %s\n", pool.hasQueuedSubmissions()); System.out.printf("Main: Fork/Join Pool: Steal Count: %d\n", pool.getStealCount()); System.out.printf("Main: Fork/Join Pool: Terminated : %s\n", pool.isTerminated()); System.out.printf("**********************\n"); } }
工作原理
本节实现了递增数组元素的任务,使用到ForkJoinPool类和继承RecursiveAction类的Task类。这是能够在ForkJoinPool类中执行的任务之一,当任务处理数组时,输出ForkJoinPool类的状态信息到控制台。通过使用如下方法得到ForkJoinPool类的状态信息:
- getPoolSize():返回ForkJoinPool类内部池的工作线程数量的int值
- getParallelism():返回为池建立的所需的并行级别
- getActiveThreadCount():返回当前执行任务的线程数量
- getRunningThreadCount():返回在任何同步机制中均未阻塞的工作线程
- getQueuedSubmissionCount():返回已经进入池中,但尚未开始执行的任务数量
- getQueuedTaskCount():返回已经进入池中且开始执行的任务数量
- hasQueuedSubmissions():返回Boolean值,指明池是否有尚未开始执行的队列任务的
- getStealCount():返回long值,指定工作线程从其它线程处窃取任务的次数
- isTerminated():返回Boolean值,指明fork/join框架是否已经完成执行
更多关注
- 第五章“Fork/Join框架”中的“创建fork/join池”小节
- 第八章“定制并发类”中的“实现为fork/join框架生成自定义线程的ThreadFactory接口”和“定制在fork/join框架中运行的任务”小节