zoukankan      html  css  js  c++  java
  • 并发6-集合

    非阻塞式集合(Nom-Blocking Collection) ConcurrentLikedDeque

      这类集合也包括添加和溢出数据的方法。如果方法不能立即被执行,则返回null或者抛出异常,但是调用这个方法的线程不会阻塞

    阻塞式集合(Blocking Collection) LikeBlockingDeque

      当即和已满或者为空时,被调用的添加或者移除方法就不能立即执行,那么调用的这个方法的线程将被阻塞,知道该方法可以被执行

    ConcurrentHashMap前需要了解HashMap的数据结构

    HashMap=数组+链表:HashMap里面就是一个类似数据的小桶(长度为3的数组,[0]:key  [1]:value  [2]:指向下一个,如果是最后一个则[3]:null)

    JDK1.8之前如果HashMap里面的数量是100万,那么如果要拿到其中一个,就很耗费性能,但是在JDK1.8(包含)之后有了红黑树的感念,当HashMap里面的数据达到分配HashMap内存的75%后会以3倍的容量进行扩展。

    private static final int MAXIMUM_CAPACITY = 1 << 30; 最大容量2的30次幂
    private static final int DEFAULT_CAPACITY = 16; 默认容量16
    static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 最大数组数量0x7fffffff(16进制)==2147483647(十进制)-8
    private static final int DEFAULT_CONCURRENCY_LEVEL = 16;默认并发级别
    private static final float LOAD_FACTOR = 0.75f;扩展因子
    static final int TREEIFY_THRESHOLD = 8;阈值,当小8时为链表,当大于等于8时为红黑树
    static final int MIN_TREEIFY_CAPACITY = 64;红黑树最小扩展
    我们可以一下put方法中的putval会发现出现了一个Synchronized关键字。其中里面还有一个静态segment内部类,它的意思就是分割的意思,默认HashMap里面的每一个元素都是进行分割。

    可以想一下,为什么使用Synchronized锁而不在使用segment进行加锁了呢?经过百度查看大佬们的博客后总结:JDK1.8(不包含)之前,用的是segment方式继承ReentrantLock,实现的原理是将集合进行分割开
    来再进行加锁,粒度比较大。而1.8之后使用Synchronized所得是链表中node(指的是一个元素对象)所以锁的更细了,粒度变小了。那么出现并发争抢的可能性还高吗?(当然会出现但是几率十分小)当多个线程争
    抢一个node对象的时候,其中一个线程再使用node对象,其他线程只是在进行自旋,如果自旋数量达到阈值会形成线程阻塞(最糟糕的状态)。但是ReentrantLock就不一样它是先getState(CAS)然后进行线程占有,
    如果没有占有到线程,那么他会直接挂起等待下次再获取。当然没获取到的时候可以进行TryLock,但是如果尝试获取锁超时或者当前线程直接中断了怎么办?难道在put的时候直接抛出InterruptedException异常?
    这样就尴尬了。说白了就是1.8的升级更合理,更优化。从原来的1/16线程使用segment对象变成了1/N线程使用当前node节点对象。当N<16的时候锁的粒度上远远小于segment,阻塞的情况要小很多很多。

    ConcurrentLinkedDeque

    public class ConllectionDemo1 {
        private static ConcurrentLinkedDeque<String> cld = new ConcurrentLinkedDeque<String>();
    
        public static void main(String args[]) throws InterruptedException {
            Thread[] add = new Thread[100];
            for (int i = 0; i < 100; i++) {
                add[i] = new Thread(()->{
                    for (int j = 0; j < 10000; j++) {
                        cld.add("element"+j);
                    }
                });
                add[i].start();
                add[i].join();
            }
            System.out.println("ADDcld:"+cld.size());
    
    
            for (int i = 0; i <100 ; i++) {
                Thread[] poll = new Thread[100];
                poll[i] = new Thread(()->{
                    for (int j = 0; j <5000 ; j++) {
                        cld.pollLast();
                        cld.pollFirst();
                    }
                });
    
                poll[i].start();
                poll[i].join();
    
            }
            System.out.println("POllcld:"+cld.size());
    
        }
    }
    

      

    LinkedBlockingDeque

    public class LinkBlockingQueueDome {
        private static LinkedBlockingDeque<String> list = new LinkedBlockingDeque<String>(3);
    
        public static void main(String args[]){
            Thread[] threads = new Thread[3];
    
            //开始往里面加
            for (int i =0; i <3 ; i++) {
                threads[i] = new Thread(()->{
                    for (int j = 0; j <5 ; j++) {
                        try {
                            list.put(j+"");
                            System.out.println(j+"里面的数量是::"+list.size()+"-----");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
                threads[i].start();
            }
    
    
            //开始从里面去
            for (int i = 0; i <5 ; i++) {
                for (int j = 0; j <3 ; j++) {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                        String str = list.take();
                        System.out.println("取出来的list:"+(str)+"里面的数量是:"+list.size());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end:"+list.size());
    
        }
    }
    

      

    LinkedTransferQueue  生产-消费

    PriorityBlockingQueue  优先级

    原子操作熟悉CAS,但是需要避免ABA问题,所以我们使用AtomicStampedReference具有状态位的原子性类进行处理

  • 相关阅读:
    自己实现迭代器
    Python基础教程(入门教程),30分钟玩转Python编程!!
    centos7安装python 与卸载python
    docker 批量导入本地 tar 镜像包的 sao 操作
    无线路由器信道怎么设置 无线路由器信道选择哪个好
    关于打包压缩几种格式(gzip,bzip2,xz)的试验对比
    linux 长期运行程序的 四种方法
    win10快捷键大全 win10常用快捷键
    linux bg和fg命令
    Apache htpasswd命令用法详解
  • 原文地址:https://www.cnblogs.com/gnwzj/p/10611508.html
Copyright © 2011-2022 走看看