当前位置:嗨网首页>书籍在线阅读

08-案例实现

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

案例实现

根据如下步骤来实现本案例:

1.创建一个名为 DocumentMock 的类。该类通过生成一个字符串型二维数组来模拟一份文档:

public class DocumentMock {

2.创建一个由多个单词组成的字符串型数组。该数组用于生成字符串型二维数组:

private String words[]={"the","hello","goodbye","packt",
                        "java","thread","pool","random",
                        "class","main"};

3.实现 generateDocument() 方法。该方法接收行数、每行的单词数和要搜索的单词作为参数,并返回一个字符串型二维数组:

public String[][] generateDocument(int numLines, int numWords,
                                   String word){

4.创建必要的对象来生成文档—二维数组 String 和用来生成随机数字的 Random 对象:

int counter=0;
String document[][]=new String[numLines][numWords];
Random random=new Random();

5.用字符串填充数组。数组的每个位置都存储字符串,数组中字符串对应的位置是随机生成的。程序要在生成的数组中查找给定单词出现的次数。开发者可以用该值来检查程序是否正确完成任务:

for (int i=0; i<numLines; i++){
  for (int j=0; j<numWords; j++) {
    int index=random.nextInt(words.length);
    document[i][j]=words[index];
    if (document[i][j].equals(word)){
      counter++;
    }
  }
}

6.打印单词出现的次数,并返回生成的二维数组:

System.out.println("DocumentMock: The word appears "+ counter+"
                    times in the document");
return document;

7.创建一个名为 DocumentTask 的类,并继承泛型类型为 IntegerRecursiveTask 类。该类实现了指定单词在行集合中出现次数的任务:

public class DocumentTask extends RecursiveTask<Integer> {

8.声明一个名为 document 的私有 String 型数组、名为 startend 的两个私有 int 型属性,并声明一个名为 word 的私有 String 型属性:

private String document[][];
private int start, end;
private String word;

9.实现该类的构造方法并初始化全部属性:

public DocumentTask (String document[][], int start, int end,
                     String word){
  this.document=document;
  this.start=start;
  this.end=end;
  this.word=word;
}

10.实现 compute() 方法。如果 endstart 属性的差小于 10 ,则该任务直接计算通过调用 processLines() 方法获得的行中,给定单词出现的次数:

@Override
protected Integer compute() {
  Integer result=null;
  if (end-start<10){
    result=processLines(document, start, end, word);

11.否则,分割行为两组,并创建两个新的 DocumentTask 对象来处理这两组行,并在池中调用 invokeAll() 方法来执行它们:

} else {
  int mid=(start+end)/2;
  DocumentTask task1=new DocumentTask(document,start,mid,word);
  DocumentTask task2=new DocumentTask(document,mid,end,word);
  invokeAll(task1,task2);

12.调用 groupResults() 方法,将两个任务返回的值相加,并返回任务执行的最终结果:

  try {
    result=groupResults(task1.get(),task2.get());
  } catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
  }
}
return result;

13.实现 processLines() 方法。该方法接收一个字符串二维数组,以 startend 属性和用于查找单词的 word 属性作为参数:

private Integer processLines(String[][] document, int start,
                             int end,String word) {

14.为任务中需要处理的每一行创建一个 LineTask 对象,并用一个任务列表来存储:

List<LineTask> tasks=new ArrayList<LineTask>();
for (int i=start; i<end; i++){
  LineTask task=new LineTask(document[i], 0,
                             document[i].length, word);
  tasks.add(task);
}

15.用 invokeAll() 方法执行全部任务:

invokeAll(tasks);

16.汇总所有任务的返回值,并返回最终结果:

int result=0;
for (int i=0; i<tasks.size(); i++) {
  LineTask task=tasks.get(i);
  try {
    result=result+task.get();
  } catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
  }
}
return result;

17.实现 groupResults() 方法。该方法将两个数组相加并返回结果:

private Integer groupResults(Integer number1,Integer number2) {
  Integer result;
  result=number1+number2;
  return result;
}

18.创建一个名为 LineTask 的类,泛型类型为 Integer 并继承 RecursiveTask 类。该类将计算一行中给定单词出现的次数:

public class LineTask extends RecursiveTask<Integer>{

19.声明一个名为 line 的私有 String 型数组,名为 startend 的两个私有 int 型属性。最后,声明一个名为 word 的私有 String 型属性:

private String line[];
private int start, end;
private String word;

20.实现该类的构造方法并初始化全部属性:

public LineTask(String line[],int start,int end,String word) {
  this.line=line;
  this.start=start;
  this.end=end;
  this.word=word;
}

21.实现该类的 compute() 方法。如果 endstart 属性的差小于 100 ,则该任务直接调用 count() 方法并在行中 startend 范围内搜索给定单词:

@Override
protected Integer compute() {
  Integer result=null;
  if (end-start<100) {
    result=count(line, start, end, word);

22.否则,将行分割为两组,并创建两个新的 LineTask 对象来处理这两组行,并在池中调用 invokeAll() 方法来执行它们:

} else {
  int mid=(start+end)/2;
  LineTask task1=new LineTask(line, start, mid, word);
  LineTask task2=new LineTask(line, mid, end, word);
  invokeAll(task1, task2);

23.调用 groupResults()方 法,将两个任务返回的值相加,并返回任务的最终结果:

  try {
    result=groupResults(task1.get(),task2.get());
  } catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
  }
}
return result;

24.实现 count() 方法。该方法接收由完整一行生成的字符串二维数组, startend 属性和用于查找单词的 word 属性作为参数:

private Integer count(String[] line, int start, int end,
                      String word) {

25.在 startend 之间,对比需要搜索的单词和数组对应位置上存储的单词。如果两个单词相同,则增加 counter 变量:

int counter;
counter=0;
for (int i=start; i<end; i++){
  if (line[i].equals(word)){
    counter++;
  }
}

26.让任务休眠10ms,从而减慢程序运行:

try {
  Thread.sleep(10);
} catch (InterruptedException e) {
  e.printStackTrace();
}

27.返回 counter 变量的值:

return counter;

28.实现 groupResults() 方法,该方法将两个数字相加并返回结果:

private Integer groupResults(Integer number1,Integer number2) {
  Integer result;
  result=number1+number2;
  return result;
}

29.至此,就可以实现应用程序的入口,创建包含 main() 方法的 Main 类:

public class Main{
  public static void main(String[] args) {

30.用 DocumentMock 类来创建一个包含100行,每行有1000个单词的文档:

DocumentMock mock=new DocumentMock();
String[][] document=mock.generateDocument(100, 1000, "the");

31.创建一个新的 DocumentTask 对象来更新整个文档。 start 参数值为 0end 参数值为 100

DocumentTask task=new DocumentTask(document, 0, 100, "the");

32.调用 commonPool() 方法获取默认的 ForkJoinPool 执行器,并调用 execute() 方法执行该任务:

ForkJoinPool commonPool=ForkJoinPool.commonPool();
commonPool.execute(task);

33.实现一个代码块,用于展示池中进程的信息。任务结束之前,每秒在控制台打印输出池中参数值一次:

do {
  System.out.printf("*************************
                     *****************\n");
  System.out.printf("Main: Active Threads: %d\n",
                    commonPool.getActiveThreadCount());
  System.out.printf("Main: Task Count: %d\n",
                    commonPool.getQueuedTaskCount());
  System.out.printf("Main: Steal Count: %d\n",
                    commonPool.getStealCount());
  System.out.printf("***********************************
                     *******\n");
  try {
    TimeUnit.SECONDS.sleep(1);
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
} while (!task.isDone());

34.调用 shutdown() 方法关闭池:

pool.shutdown();

35.调用 awaitTermination() 方法等待程序执行完成:

try {
  pool.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
  e.printStackTrace();
}

36.打印文档中单词出现的次数,检查该数字是否和 DocumentMock 类中获取的数字相同:

try {
  System.out.printf("Main: The word appears %d in the
                     document",task.get());
} catch (InterruptedException | ExecutionException e) {
  e.printStackTrace();
}