zoukankan      html  css  js  c++  java
  • 并发容器

    1.大纲

      集合类的历史

      ConcurrentHashMap

      CopyConWriteArrayList  

      并发队列

      

    一:容器的概览

    1.概览

      ConcurrentHashMap:线程安全的HashMap  

      CopyOnWriteArrayList:线程安全的List

      BlockingQueue:这是一个接口,表示阻塞队列

      ConcurrentLinkedQueue:高效的非阻塞并发队列,线程安全的,可以看做一个线程安全的LinkedList

      ConcurrentSkipListMap:是一个map,使用跳表数据结构进行快速查找

    二:集合历史

    1.vector与Hashtable

      vector:

    package com.jun.juc.collections;
    
    import java.util.Vector;
    
    public class VectorDemo {
        public static void main(String[] args) {
            Vector vector = new Vector();
            vector.add("test");
            System.out.println(vector.get(0));
        }
    }
    

      看一下get方法

        public synchronized E get(int index) {
            if (index >= elementCount)
                throw new ArrayIndexOutOfBoundsException(index);
    
            return elementData(index);
        }
    

      结论:

      这个是在方法上加了锁,继续看其他的方法,发现也是在方法是加的锁。

      Hashtable:

    public class HashtableDemo {
        public static void main(String[] args) {
            Hashtable<String, String> stringStringHashtable = new Hashtable<>();
            stringStringHashtable.put("aa", "1111");
            System.out.println(stringStringHashtable.get("aa"));
        }
    }
    

      看一下对应的get方法:

        public synchronized V get(Object key) {
            Entry<?,?> tab[] = table;
            int hash = key.hashCode();
            int index = (hash & 0x7FFFFFFF) % tab.length;
            for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
                if ((e.hash == hash) && e.key.equals(key)) {
                    return (V)e.value;
                }
            }
            return null;
        }
    

      结论

      也是在方法上加的锁进行实现的

    2.ArrayList与HashMap  

      是线程不安全的,可以使用如下的方法使得安全:

      Collections.synchronizedList(new ArrayList<>())

      Collections.synchronizedMap(new HashMap<>())

    示例:

    package com.jun.juc.collections;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class SynchronizedListAndMap {
        public static void main(String[] args) {
            List<String> strList = Collections.synchronizedList(new ArrayList<String>());
            strList.add("tom");
        }
    }
    

      进入:

        public static <T> List<T> synchronizedList(List<T> list) {
            return (list instanceof RandomAccess ?
                    new SynchronizedRandomAccessList<>(list) :
                    new SynchronizedList<>(list));
        }
    

      这个时候,看一下ArrayList:

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    

      所以,走第一个对象,然后再进去看:

        /**
         * @serial include
         */
        static class SynchronizedRandomAccessList<E>
            extends SynchronizedList<E>
            implements RandomAccess {
    
            SynchronizedRandomAccessList(List<E> list) {
                super(list);
            }
    

      看父类:

        /**
         * @serial include
         */
        static class SynchronizedList<E>
            extends SynchronizedCollection<E>
            implements List<E> {
            private static final long serialVersionUID = -7754090372962971524L;
    
            final List<E> list;
    
            SynchronizedList(List<E> list) {
                super(list);
                this.list = list;
            }
            SynchronizedList(List<E> list, Object mutex) {
                super(list, mutex);
                this.list = list;
            }
    
            public boolean equals(Object o) {
                if (this == o)
                    return true;
                synchronized (mutex) {return list.equals(o);}
            }
            public int hashCode() {
                synchronized (mutex) {return list.hashCode();}
            }
    
            public E get(int index) {
                synchronized (mutex) {return list.get(index);}
            }
            public E set(int index, E element) {
                synchronized (mutex) {return list.set(index, element);}
            }
            public void add(int index, E element) {
                synchronized (mutex) {list.add(index, element);}
            }
            public E remove(int index) {
                synchronized (mutex) {return list.remove(index);}
            }
    
            public int indexOf(Object o) {
                synchronized (mutex) {return list.indexOf(o);}
            }
            public int lastIndexOf(Object o) {
                synchronized (mutex) {return list.lastIndexOf(o);}
            }
    
            public boolean addAll(int index, Collection<? extends E> c) {
                synchronized (mutex) {return list.addAll(index, c);}
            }
    
            public ListIterator<E> listIterator() {
                return list.listIterator(); // Must be manually synched by user
            }
    
            public ListIterator<E> listIterator(int index) {
                return list.listIterator(index); // Must be manually synched by user
            }
    
            public List<E> subList(int fromIndex, int toIndex) {
                synchronized (mutex) {
                    return new SynchronizedList<>(list.subList(fromIndex, toIndex),
                                                mutex);
                }
            }
    
            @Override
            public void replaceAll(UnaryOperator<E> operator) {
                synchronized (mutex) {list.replaceAll(operator);}
            }
            @Override
            public void sort(Comparator<? super E> c) {
                synchronized (mutex) {list.sort(c);}
            }
    
            /**
             * SynchronizedRandomAccessList instances are serialized as
             * SynchronizedList instances to allow them to be deserialized
             * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList).
             * This method inverts the transformation.  As a beneficial
             * side-effect, it also grafts the RandomAccess marker onto
             * SynchronizedList instances that were serialized in pre-1.4 JREs.
             *
             * Note: Unfortunately, SynchronizedRandomAccessList instances
             * serialized in 1.4.1 and deserialized in 1.4 will become
             * SynchronizedList instances, as this method was missing in 1.4.
             */
            private Object readResolve() {
                return (list instanceof RandomAccess
                        ? new SynchronizedRandomAccessList<>(list)
                        : this);
            }
        }
    

      结论:

      发现是使用代码块的方式进行的安全。

    三:ConcurrentHashMap

    1.Map的介绍

      

       说明一下LinkedHashMap:

      大多数情况下,只要不涉及线程安全问题,Map基本都可以使用HashMap,不过HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序。HashMap的这一缺点往往会带来困扰,因为有些场景,我们期待一个有序的Map。

    这个时候,LinkedHashMap就闪亮登场了,它虽然增加了时间和空间上的开销,但是通过维护一个运行于所有条目的双向链表,LinkedHashMap保证了元素迭代的顺序该迭代顺序可以是插入顺序或者是访问顺序。

      

    2.为什么HashMap是线程不安全的

      同时put碰撞会导致数据的丢失

      同时put扩容会导致数据的丢失

      死循环造成的cpu100%

    3.为什么出现100%

      主要存在于jdk7

      需要使用多线程进行调试

    package com.jun.juc.collections;
    
    import java.util.HashMap;
    
    /**
     * 演示cpu100%
     */
    public class HashMapLoop {
        private static HashMap<Integer, String> map = new HashMap(2, 1.5f);
    
        public static void main(String[] args) {
            map.put(1, "A");
            map.put(2, "B");
            map.put(3, "C");
            new Thread(new Runnable() {
                @Override
                public void run() {
                    map.put(4, "D");
                    System.out.println(map);
                }
            }, "thread1").start();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    map.put(5, "E");
                    System.out.println(map);
                }
            }, "thread1").start();
        }
    }
    

      

      需要的断点:

      

       然后,将两个线程都放到if()那行,然后都放行

      原因:

      因为在同时扩容时候,出现了链表的死循环,环形链表

    4.

  • 相关阅读:
    关于Git的使用方法
    Python读取Excel数据
    用到的Dos命令总结 持续更新
    windows下使用Jenkins+Gitea持续集成
    HDFS概述(2)————Block块大小设置
    分布式文件系统比较出名的有HDFS  和 GFS
    c++里面有没有什么办法做到 判断某个给定的未知数是double类型还是int类型 呢?
    About HDFS blocks
    hadoop深入学习之SequenceFile
    使用RawComparator加速Hadoop程序
  • 原文地址:https://www.cnblogs.com/juncaoit/p/13155518.html
Copyright © 2011-2022 走看看