008. J.U.C 之并发容器类 Map

1. JDK 源码学习方法


1. 演绎推导法
  • 示例:因果推理。
  • 因为 JAVA 中只提供了 BIO 和 NIO 两种方式,所以一切框架中,涉及到网络处理的,都可以用这两个知识点去探究原理。
2. 归纳总结法
  • 示例:可能正确的猜想。
  • 线上 10 台服务器,有 3 台总是每天自动会重启,收集相关信息后,发现是运维在修改监控系统配置的时候,漏掉了提高这 3 台机器的重启阀值。
3. 类比法
  • 集群概念就好像是马在拉车,一匹马拉不动的时候,就使用多匹马去拉。
  • 分布式的概念,就像是理发的过程中,洗头发和剪头发是不同的人负责的。

2. 推理 HashMap 的实现


1. 涉及内容
  1. 数据要存储

    • 涉及到数据结构:数组、链表、栈、树、队列。
  2. 数组的插入和查找

    • 顺序查找:插入时按先后顺序插入,查找时轮询扫描进行对比。
    • 二分查找:插入时进行排序;查找时将 n 个元素分成大致相等的两部分,减少复杂度。
    • 分块查找:分块查找是二分查找和顺序查找的一种改进。
    • 哈希表:对元素的关键信息进行 hash 计算,求出下标后直接插入或查找。常用的实现是除留余数法。
  3. 哈希冲突,数组位置已存在值。

    • hash(key2)=hash(key1)。链地址法;ReHash1(key2) 再次计算 hash;
  4. 合理控制数组和链表的长度。

    • 动态扩容 resize()。
2. HashMap(JDK1.7)

img

3. HashMap(JDK1.8)
  • JDK1.8 后,HashMap 中链表中元素超过一个数量后,转变为红黑树结构。

img

3. ConcurrentHashMap


1. JDK1.7

img

2. JDK1.8

img

4. ConcurrentSkipListMap


img

4. List


1. CopyOnWriteArrayList 优缺点
  • CopyOnWriteArrayList 容器即写时复制的容器。
  • 优点:
    • 和 ArrayList 比较,优点是并发安全,
  • 缺点:
    • 多了内存占用:写数据是 copy 一份完整的数据,单独进行操作。占用双份内存。
    • 数据一致性:数据写完之后,其他线程不一定马上能读取到最新内容。
2. CopyOnWriteArrayList 原理分析

img

img

img

5. Set


实现原理特点
HashSet基于 HashMap 实现非线程安全
CopyOnWriteArraySet基于 CopyOnWriteArrayList线程安全
ConcurrentSkipListSet基于 ConcurrentSkipListMap 实现线程安全,有序,查询快

6. Queue


1. Queue API
  • Queue - 队列数据结构的实现。分为阻塞队列和非阻塞队列。下列蓝色区块,为阻塞队列特有方法。

img

2. 常用队列
  • ArrayBlockingQueue
  • LinkedBlockingQueue
  • ConcurrentLinkedQueue (并发行更好,cas 机制)
  • SynchronousQueue
  • PriorityBlockingQueue
3. SynchronousQueue(同步队列)
  1. take会阻塞,直到取到元素

    public static void test01() throws InterruptedException {
        new Thread(() -> {
            try {
                Thread.sleep(3000);
                syncQueue.put("put_element");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    
        System.out.println("begin to take...");
        System.out.println(syncQueue.take());
        System.out.println("take done...");
    }
    
  2. put 时被阻塞,直到被 get

    public static void test02() throws InterruptedException {
        new Thread(() -> {
            try {
                Thread.sleep(3000);
                System.out.println(syncQueue.poll());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    
        System.out.println("begin to put...");
        syncQueue.put("put_element");
        System.out.println("put done...");
    }
    
  3. 若没有 take 方法阻塞等待,offer 的元素可能会丢失

    public static void test03() {
        syncQueue.offer("offered_element");
        System.out.println(syncQueue.poll());
    }
    
  4. poll 取不到元素,就返回 null,如果正好有 put 被阻塞,可以取到

    public static void test04() throws InterruptedException {
        new Thread(() -> {
            try {
                syncQueue.put("put_element");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    
        Thread.sleep(1000);
        Object obj = syncQueue.poll();
        System.out.println(obj);
    }
    
  5. peek 永远只能取到 null,不能让 take 结束阻塞

    public static void test05() throws InterruptedException {
        new Thread(() -> {
            try {
                syncQueue.put("put_element");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    
        Thread.sleep(200L);
        Object obj =  syncQueue.peek();
        System.out.println(obj);
    
    }
    
4. PriorityBlockingQueue(优先级队列)
  1. 简单使用

    public static void main(String[] args) {
        PriorityBlockingQueue<String> queue = new PriorityBlockingQueue<>();
    
        queue.put("48");
        queue.put("01");
        queue.put("12");
        queue.put("27");
    
        queue.put("31");
    
        for (;queue.size() > 0;) {
            try {
                System.out.println(queue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
  2. 自定义比较规则

    public class Demo4_PriorityBlockingQueue {
        static PriorityBlockingQueue<Student> queue = new PriorityBlockingQueue<>(5,
                // (stu1, stu2) -> stu1.age - stu2.age
                Comparator.comparingInt(stu -> stu.age)
        );
    
        public static void main(String[] args) throws InterruptedException {
            queue.put(new Student(10, "Emily"));
            queue.put(new Student(20, "Tony"));
            queue.put(new Student(5, "Baby"));
    
            for (; queue.size() > 0;) {
                System.out.println(queue.take().name);
            }
        }
    }
    
    class Student {
        public int age;
        public String name;
    
        public Student(int age, String name) {
            this.age = age;
            this.name = name;
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值