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

35-案例实现

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

案例实现

根据如下步骤实现本案例。

1.创建 Person 类,它包含6个定义一个人基本特征的属性,为这些属性添加 get()set() 方法。

public class Person {
  private int id;
  private String firstName;
  private String lastName;
  private Date birthDate;
  private int salary;
  private double coeficient;

2.实现 PersonGenerator 类,它只有一个 generatedPersonList() 方法,该方法生成一个包含拥有随机属性值的 Person 对象列表。

public class PersonGenerator {
  public static List<Person> generatePersonList (int size) {
    List<Person> ret = new ArrayList<>();
    String firstNames[] = {"Mary","Patricia","Linda",
                           "Barbara","Elizabeth","James",
                           "John","Robert","Michael","William"};
    String lastNames[] = {"Smith","Jones","Taylor",
                          "Williams","Brown","Davies",
                          "Evans","Wilson","Thomas","Roberts"};
    Random randomGenerator=new Random();
    for (int i=0; i<size; i++) {
      Person person=new Person();
      person.setId(i);
      person.setFirstName(firstNames
                               [randomGenerator.nextInt(10)]);
      person.setLastName(lastNames
                             [randomGenerator.nextInt(10)]);
      person.setSalary(randomGenerator.nextInt(100000));
      person.setCoeficient(randomGenerator.nextDouble()*10);
      Calendar calendar=Calendar.getInstance();
      calendar.add(Calendar.YEAR, -randomGenerator
                                             .nextInt(30));
      Date birthDate=calendar.getTime();
      person.setBirthDate(birthDate);
      ret.add(person);
    }
    return ret;
  }
}

3.实现一个任务类 PersonMapTask 。它主要把列表中的人转换到 map 中, map 中的 key 是人名, valueList<Person> ,其中存放着和 key 一样名字的人。由于转换过程使用fork/join框架来实现,因此 PersonMapTask 要继承 RecursiveAction 类:

public class PersonMapTask extends RecursiveAction {

4. PersonMapTask 包含两个私有属性:待处理的 List<Person> 对象和存放着处理结果的 ConcurrentHashMap 。用构造器初始化这两个属性:

private List<Person> persons;
private ConcurrentHashMap<String, ConcurrentLinkedDeque
                                        <Person>> personMap;
public PersonMapTask(List<Person> persons, ConcurrentHashMap
           <String, ConcurrentLinkedDeque<Person>> personMap) {
  this.persons = persons;
  this.personMap = personMap;
}

5.实现 compute() 方法。如果列表中少于1000个元素,那么就直接把这些元素插入到 ConcurrentHashMap 中。使用 computeIfAbsent() 方法在 map 上计算 key 关联的列表是否存在,如果不存在那么就创建一个新的 ConcurrentLinkedDeque 对象:

protected void compute() {
  if (persons.size() < 1000) {
    for (Person person: persons) {
      ConcurrentLinkedDeque<Person> personList=personMap
             .computeIfAbsent(person.getFirstName(), name -> {
      return new ConcurrentLinkedDeque<>();
      });
      personList.add(person);
    }
    return;
  }

6.如果列表中的元素多于1000个,则创建两个子任务,分别将列表的一部分委托给它们处理:

  PersonMapTask child1, child2;
  child1=new PersonMapTask(persons.subList(0,persons.size()/2),
                           personMap);
  child2=new PersonMapTask(persons.subList(persons.size()/2,
                                           persons.size()),
                           personMap);
    invokeAll(child1,child2);
  }
}

7.实现 Main 类,创建 main() 方法,生成一个包含100000个随机 Person 对象的列表:

public class Main {
  public static void main (String[] args) {
    List<Person> persons=PersonGenerator
                                .generatePersonList(100000);

8.接下来开始比较。我们以两种方式生成了 Map ——它们都以人名作为 key ,以部分人员作为 value 。第一种方式在列表上调用 parallelStream() 获取并行流,并在 collect() 方法中使用 groupingByConcurrent() 收集器:

Date start, end;
start =  new Date();
Map<String, List<Person>> personsByName = persons
                                          .parallelStream()
.collect(Collectors.groupingByConcurrent(p -> p
                                           .getFirstName()));
end = new Date();
System.out.printf("Collect: %d - %d\n", personsByName.size(),
                  end.getTime()-start.getTime());

第二种方式是使用 fork/join 框架和 PersonMapTask 类:

  start = new Date();
  ConcurrentHashMap<String, ConcurrentLinkedDeque<Person>>
                forkJoinMap=new ConcurrentHashMap<>();
  PersonMapTask personMapTask=new PersonMapTask
                                  (persons,forkJoinMap);
  ForkJoinPool.commonPool().invoke(personMapTask);
  end = new Date();
  System.out.printf("Collect ForkJoinPool: %d - %d\n",
                    forkJoinMap.size(),
                    end.getTime()-start.getTime());
  }
}