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
是人名, value
是 List<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());
}
}