1)找到大于某key的元素ceilingEntry
package org.example.basic;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
public class TestNavigableMap {
public static void main(String[] args) {
// 实现SortedMap
NavigableMap<Integer, String> map = new TreeMap<>();
map.put(10, "ten");
map.put(2, "two");
map.put(7, "seven");
map.put(3, "three");
map.put(8, "eight");
map.put(9, "nine");
map.put(7, "seven1");
Map.Entry<Integer, String> entry = map.ceilingEntry(6);
System.out.println(entry);
}
}
/*
7=seven1
*/
由于实现了NavigableMap接口。
2)一致hash
package org.example.testconsistenthash;
import java.util.Map;
import java.util.TreeMap;
public class Main {
private static TreeMap<Integer, String> map = new TreeMap<>();
public static void main(String[] args) {
// 模拟初始化一组业务服务器
map.put(11, "server1");
map.put(33, "server3");
map.put(22, "server2");
map.put(55, "server5");
map.put(44, "server4");
// 根据一致性算法,如:玩家的uid 或者 聊天的groupId等作为一致性hash
// 模拟计算这条消息应该往哪个业务服务器转发
System.out.println(getServerName(30));
System.out.println(getServerName(33));
System.out.println(getServerName(34));
System.out.println(getServerName(100));
}
public static String getServerName(Integer hash) {
if (map.size() == 0) {
return null;
}
Map.Entry<Integer, String> entry = map.ceilingEntry(hash);
if (entry != null) {
return entry.getValue();
}
return map.firstEntry().getValue();
}
}
/*
server3
server3
server4
server1
*/
可以看出来,随便新增服务器,我hash一样的,始终会找到相同的服务器。
理解:
TreeMap相当于能根据key进行排序,默认是字典顺序。这里没有传递排序函数,因此就是从小到大排序。
同时TreeMap提供的有ceilingEntry保证取到最近的。
一致性hash的缺点:增删节点时,可能会引起其中一个数据路由错误,因此一致性hash比普通的hash取模只是将所有的路由错误改为有一次路由错误,并不能完全解决路由问题。
3)警惕HashMap扩充后的问题
情景:配置的实现是:Map,然后插入sn,然后将values()转为List让程序使用,由于sn都是整形的,那么findAll()是有序的吗?
例子1:测试下
package org.example.TestSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;
public class Main {
public static class A implements Comparable<A> {
private int val;
public A(int val) {
this.val = val;
}
public int getVal() {
return val;
}
@Override
public int compareTo(A o) {
return val - o.val;
}
@Override
public String toString() {
return "A{" +
"val=" + val +
'}';
}
}
public static void main(String[] args) {
// 有序,根据key排序
Map<Integer, A> treeMap = Maps.newTreeMap();
// 无序!!!
// Map<Integer, A> treeMap = Maps.newHashMap();
for (int i = 1; i < Integer.MAX_VALUE / 1000; i++) {
treeMap.put(i, new A(i));
}
List<A> list = Lists.newArrayList(treeMap.values());
for (int i = 0; i < list.size() - 1; i++) {
int cur = list.get(i).getVal();
int next = list.get(i + 1).getVal();
int diff = next - cur;
if (diff < 0) {
System.out.println("i = " + i + " diff = " + diff + " cur = " + cur + " next = " + next);
}
}
}
}
/*
Map的时候:// 第一个是65535
i = 707332 diff = -3 cur = 707343 next = 707340
i = 707334 diff = -11 cur = 707341 next = 707330
i = 707336 diff = -3 cur = 707331 next = 707328
i = 707340 diff = -3 cur = 707335 next = 707332
i = 707344 diff = -3 cur = 707355 next = 707352
i = 707348 diff = -3 cur = 707359 next = 707356
i = 707350 diff = -11 cur = 707357 next = 707346
i = 707352 diff = -3 cur = 707347 next = 707344
i = 707356 diff = -3 cur = 707351 next = 707348
TreeMap则是绝对的有序
*/
可以看出来:Map在有65535个元素后,顺序就会变化了。
4)根据跨服天数查某天的奖励,请使用TreeMap
package org.example.TestSet;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.TreeMap;
public class Main {
public static class Conf implements Comparable<Conf> {
private int val;
public Conf(int val) {
this.val = val;
}
public int getVal() {
return val;
}
@Override
public int compareTo(Conf o) {
return val - o.val;
}
@Override
public String toString() {
return "Conf{" +
"val=" + val +
'}';
}
}
public static void main(String[] args) {
TreeMap<Integer, Conf> treeMap = Maps.newTreeMap();
treeMap.put(4, new Conf(4));
treeMap.put(14, new Conf(14));
treeMap.put(8, new Conf(8));
treeMap.put(9999, new Conf(9999));
treeMap.put(54, new Conf(54));
System.out.println(getConf(treeMap, 3));
System.out.println(getConf(treeMap, 8));
System.out.println(getConf(treeMap, 53));
System.out.println(getConf(treeMap, 9999999));
}
public static Conf getConf(TreeMap<Integer, Conf> treeMap, Integer key) {
Map.Entry<Integer, Conf> entry = treeMap.ceilingEntry(key);
if (entry != null) {
return entry.getValue();
}
return treeMap.lastEntry().getValue();
}
}
/*
Conf{val=4}
Conf{val=8}
Conf{val=54}
Conf{val=9999}
*/
--
package org.example.testTreeMap;
import com.google.common.collect.Maps;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
TreeMap<Integer, Integer> treeMap = Maps.newTreeMap();
treeMap.put(4, 5);
treeMap.put(8, 15);
treeMap.put(14, 10);
System.out.println(treeMap.ceilingEntry(1));
System.out.println(treeMap.ceilingEntry(4));
System.out.println(treeMap.ceilingEntry(8));
System.out.println(treeMap.ceilingEntry(10));
System.out.println(treeMap.ceilingEntry(20));
}
}
/*
4=5
4=5
8=15
14=10
null
*/