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

24-案例实现

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

案例实现

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

1.创建一个 Operation 类,并实现3个字段:一个 String 类型的 user 字段、一个 String 类型的 operation 字段和一个 Date 类型的 time 字段。同时给这些字段分别实现 gettersetter 方法。由于该类结构比较简单,因此在此不予展示。

2.创建一个 HashFiller 类并实现 Runnable 接口:

public class HashFiller implements Runnable {

3.声明一个 ConcurrentHashMap 类型的 userHash 私有字段。该类的 keyString 类型,而其 value 则为 ConcurrentLinkedDeque<Operation> 类型。同时,实现该类的一个构造方法来初始化字段:

private ConcurrentHashMap<String, ConcurrentLinkedDeque<Operation>>
        userHash;
public HashFiller(ConcurrentHashMap<String, ConcurrentLinkedDeque
                  <Operation>> userHash) {
  this.userHash = userHash;
}

4.实现 run() 方法。在方法中给 ConcurrentHashMap 填充100个随机的 Operation 对象。首先生成随机数据,然后用 addOperationToHash() 方法来插入对象到散列中:

@Override
public void run() {
  Random randomGenerator=new Random();
  for (int i=0; i<100; i++) {
    Operation operation=new Operation();
    String user = "USER" + randomGenerator.nextInt(100);
    operation.setUser(user);
    String action = "OP" + randomGenerator.nextInt(10);
    operation.setOperation(action);
    operation.setTime(new Date());
    addOperationToHash(userHash, operation);
  }
}

5.实现 addOperationToHash() 方法。它以 hashoperation 作为参数。map的key是与operation对应的user。用 computeIfAbsent() 方法可以关联key和对应的 ConcurrentLinkedDeque 对象。如果key已存在,则该方法将返回对应的value;否则,将会执行方法上的参数,该参数是一个lambda表达式,它生成与key相对应的value。在本案例中,它将生成一个新的 ConcurrentLinkedDeque 对象。最后,插入operation到队列中:

private void addOperationToHash(ConcurrentHashMap<String,
                                ConcurrentLinkedDeque<Operation>> 
                                userHash, Operation operation) {
  ConcurrentLinkedDeque<Operation> opList = userHash
                           .computeIfAbsent(operation.getUser(),
                           user -> new ConcurrentLinkedDeque<>());
  opList.add(operation);
}

6.实现 Main 类和它的 main() 方法。首先,声明 ConcurrentHashMap 对象和 HashFiller 对象:

ConcurrentHashMap<String, ConcurrentLinkedDeque<Operation>>
  userHash = new ConcurrentHashMap<>();
HashFiller hashFiller = new HashFiller(userHash);

7.执行10个带 HashFiller 类的线程,并用 join() 方法等待它们执行完成:

Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
  threads[i] = new Thread(hashFiller);
  threads[i].start();
}
for (int i = 0; i < 10; i++) {
  try {
    threads[i].join();
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
}

8.现在,把关于 ConcurrentHashMap 的信息抽取出来。首先,从 size() 方法中获取元素的个数。然后,用 forEach() 方法遍历散列中的所有元素。第一个参数是并发阈值,而且它还是元素的最小值,它要求代码操作用并发的方式来执行。因为已经给定了值为10的并发阈值以及有100个元素的散列,所以该操作将会以并发的方式来执行。lambda表达式接收了两个参数:key和value。打印key和作为value的 ConcurrentLinkedDeque 的长度:

System.out.printf("Size: %d\n", userHash.size());
userHash.forEach(10, (user, list) -> {
  System.out.printf("%s: %s: %d\n", Thread.currentThread()
                    .getName(), user, list.size());
});

9.调用 forEachEntry() 方法。虽然它跟前一个方法很相似,但是其lambda表达式接收的参数是一个 Entry 对象,取代了之前接收的两个参数。因此,可以用entry对象来获取其key和value:

userHash.forEachEntry(10, entry -> {
  System.out.printf("%s: %s: %d\n", Thread.currentThread()
                    .getName(), entry.getKey(),
  entry.getValue().size());
});

10.调用 search() 方法来查找第一个满足指定查询条件的元素。在本案例中,查询条件是搜索一个 code 末尾字符为1的operation。与 forEach() 方法类似,该方法可以指定一个并发阈值:

Operation op = userHash.search(10, (user, list) -> {
  for (Operation operation : list) {
    if (operation.getOperation().endsWith("1")) {
      return operation;
    }
  }
  return null;
});
System.out.printf("The operation we have found is: %s, %s, %s,\n",
                  op.getUser(), op.getOperation(), op.getTime());

11.再次使用 search() 方法。但这次,要查询多于10个operation的user:

ConcurrentLinkedDeque<Operation> operations = userHash.search(10, 
                                                  (user, list) -> {
  if (list.size() > 10) {
    return list;
  }
  return null;
});
System.out.printf("The user we have found is: %s: %d operations\n",
                  operations.getFirst().getUser(),
                  operations.size());

12.用 reduce() 方法来计算保存在散列里面的operation总值:

    int totalSize = userHash.reduce(10, (user, list) -> {
      return list.size();
    }, (n1, n2) -> {
      return n1 + n2;
    });
    System.out.printf("The total size is: %d\n", totalSize);
  }
}