[TreeMap] 1.ceilingEntry找大于key的元素 2.一致hash 3.思考HashMap顺序问题 4.跨服天数查找配置

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
 */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值