本节讲述 ConcurrentNavigableMap 接口。实现了此接口的类存储以下2部分元素:
每部分在不同的类中实现。
Java API 也 提供了一个实现了此接口的类,就是 ConcurrentSkipListMap,它实现了一个非阻塞列表且拥有 ConcurrentNavigableMap 接口的行为。 在内部,它使用了一个 Skip List来存储数据。Skip List是一个基于并行列表的数据结构,效率类似二叉树。 作为一个排序的数据结构,它的插入、搜索、删除元素的速度比排序列表要快。
Skip List 由 William Pugh 在 1990 年引入
当插入数据到映射表,它使用key来对数据排序,所以所有元素都将被排好序。 除了返回具体的元素,此类也提供了方法来获取映射表的一个子映射表。
本节的示例代码在 com.elanzone.books.noteeg.chpt6.sect06 package中
数据类 : Contact
public class Contact { private String name; private String phone; public Contact(String name, String phone) { this.name = name; this.phone = phone; } public String getName() { return name; } public String getPhone() { return phone; } }
Runnable 实现类 : Task
ConcurrentSkipListMap<String, Contact> map; private String id; public Task(ConcurrentSkipListMap<String, Contact> map, String id) { this.map = map; this.id = id; }
for (int i = 0; i < 1000; i++) { Contact contact = new Contact(id, String.valueOf(i + 1000)); map.put(id + contact.getPhone(), contact); }
控制类 : Main
ConcurrentSkipListMap<String, Contact> map = new ConcurrentSkipListMap<>(); Thread threads[] = new Thread[25]; int count = 0; for (char i = 'A'; i < 'Z'; i++) { Task task = new Task(map, String.valueOf(i)); threads[count] = new Thread(task); threads[count].start(); count++; } for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } }
System.out.printf("Main: Size of the map: %d\n", map.size()); Map.Entry<String, Contact> element; Contact contact; element = map.firstEntry(); contact = element.getValue(); System.out.printf("Main: First Entry: %s: %s\n", contact.getName(), contact.getPhone());
element = map.lastEntry(); contact = element.getValue(); System.out.printf("Main: Last Entry: %s: %s\n", contact.getName(), contact.getPhone());
System.out.printf("Main: Submap from A1996 to B1002: \n"); ConcurrentNavigableMap<String, Contact> submap = map.subMap("A1996", "B1002"); do { element = submap.pollFirstEntry(); if (element != null) { contact = element.getValue(); System.out.printf("%s: %s\n", contact.getName(), contact. getPhone()); } } while (element != null);
本例实现了一个 Task 类来存储 Contact 对象到可导航映射表。 每个联系人的名称是创建它的任务的Id和电话号码(从1000到2000的数字)。两者拼在一起组成了联系人在映射表中的 key 。 每个任务创建 1000 个联系人并用 put() 方法保存到可导航映射表。
如果您插入一个key已经在映射表中存在的元素,此key对应的元素将被新插入的元素代替。
Main 类的 main() 方法创建 25 个 Task 对象,使用字母 A 到 Z 作为ID。然后使用了某些方法从映射表中获取数据。
ConcurrentSkipListMap 类还有一些其他的方法: