精华内容
下载资源
问答
  • 1.TreeSet,基于TreeMap线程安全的红黑树数据结构。在线程不安全访问时,有可能出现死循环。 ... android p里面RunningTasks.java...

    1.TreeSet,基于TreeMap线程不安全的红黑树数据结构。在线程不安全访问时,有可能出现死循环。

    https://ivoanjo.me/blog/2018/07/21/writing-to-a-java-treemap-concurrently-can-lead-to-an-infinite-loop-during-reads/

    android p里面RunningTasks.java里面使用的TreeSet 就会有这种情况。

    可以用Collections的辅助api来加上同步保护,注意要在set interrate的时候还要加上同步。 

        /**
         * Returns a synchronized (thread-safe) sorted set backed by the specified
         * sorted set.  In order to guarantee serial access, it is critical that
         * <strong>all</strong> access to the backing sorted set is accomplished
         * through the returned sorted set (or its views).<p>
         *
         * It is imperative that the user manually synchronize on the returned
         * sorted set when iterating over it or any of its <tt>subSet</tt>,
         * <tt>headSet</tt>, or <tt>tailSet</tt> views.
         * <pre>
         *  SortedSet s = Collections.synchronizedSortedSet(new TreeSet());
         *      ...
         *  synchronized (s) {
         *      Iterator i = s.iterator(); // Must be in the synchronized block
         *      while (i.hasNext())
         *          foo(i.next());
         *  }
         * </pre>
         * or:
         * <pre>
         *  SortedSet s = Collections.synchronizedSortedSet(new TreeSet());
         *  SortedSet s2 = s.headSet(foo);
         *      ...
         *  synchronized (s) {  // Note: s, not s2!!!
         *      Iterator i = s2.iterator(); // Must be in the synchronized block
         *      while (i.hasNext())
         *          foo(i.next());
         *  }
         * </pre>
         * Failure to follow this advice may result in non-deterministic behavior.
         *
         * <p>The returned sorted set will be serializable if the specified
         * sorted set is serializable.
         *
         * @param  <T> the class of the objects in the set
         * @param  s the sorted set to be "wrapped" in a synchronized sorted set.
         * @return a synchronized view of the specified sorted set.
         */
        public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s) {
            return new SynchronizedSortedSet<>(s);
        }

     2.ArrayList

    ArrayList考虑到线程安全的话可以直接换用Vector,或者也用Collections的api添加synchronized同步锁。

        /**
         * Returns a synchronized (thread-safe) list backed by the specified
         * list.  In order to guarantee serial access, it is critical that
         * <strong>all</strong> access to the backing list is accomplished
         * through the returned list.<p>
         *
         * It is imperative that the user manually synchronize on the returned
         * list when iterating over it:
         * <pre>
         *  List list = Collections.synchronizedList(new ArrayList());
         *      ...
         *  synchronized (list) {
         *      Iterator i = list.iterator(); // Must be in synchronized block
         *      while (i.hasNext())
         *          foo(i.next());
         *  }
         * </pre>
         * Failure to follow this advice may result in non-deterministic behavior.
         *
         * <p>The returned list will be serializable if the specified list is
         * serializable.
         *
         * @param  <T> the class of the objects in the list
         * @param  list the list to be "wrapped" in a synchronized list.
         * @return a synchronized view of the specified list.
         */
        public static <T> List<T> synchronizedList(List<T> list) {
            return (list instanceof RandomAccess ?
                    new SynchronizedRandomAccessList<>(list) :
                    new SynchronizedList<>(list));
        }

     

    展开全文
  • 作者:a60782885blog.csdn.net/a60782885/article/details/77803757对于Java并发编程,一般来说有以下的关注点:线程安全性,正确性。线程的活跃性(死锁,活锁)性能其中线程的安全性问题是首要解决的问题,线程不...

    点击上方“Java小组”,选择“星标”

    IT技术文章第一时间送达!

    作者:a60782885

    blog.csdn.net/a60782885/article/details/77803757

    对于Java并发编程,一般来说有以下的关注点:

    1. 线程安全性,正确性。

    2. 线程的活跃性(死锁,活锁)

    3. 性能

    其中线程的安全性问题是首要解决的问题,线程不安全,运行出来的结果和预期不一致,那就连基本要求都没达到了。

    保证线程的安全性问题,本质上就是保证线程同步,实际上就是线程之间的通信问题。我们知道,在操作系统中线程通信有以下几种方式:

    1. 信号量

    2. 信号

    3. 管道

    4. 共享内存

    5. 消息队列

    6. socket

    java中线程通信主要使用共享内存的方式。共享内存的通信方式首先要关注的就是可见性和有序性。而原子性操作一般都是必要的,所以主要关注这三个问题。

    1.原子性

    原子性是指操作是不可分的。其表现在于对于共享变量的某些操作,应该是不可分的,必须连续完成。例如a++,对于共享变量a的操作,实际上会执行三个步骤:

    1. 读取变量a的值

    2. a的值+1

    3. 将值赋予变量a 。

    这三个操作中任何一个操作过程中,a的值被人篡改,那么都会出现我们不希望出现的结果。所以我们必须保证这是原子性的。Java中的锁的机制解决了原子性的问题。

    2.可见性

    可见性是值一个线程对共享变量的修改,对于另一个线程来说是否是可以看到的。

    为什么会出现这种问题呢?

    我们知道,java线程通信是通过共享内存的方式进行通信的,而我们又知道,为了加快执行的速度,线程一般是不会直接操作内存的,而是操作缓存。

    java线程内存模型:

    53e462647c219263dbc8293586045625.png

    实际上,线程操作的是自己的工作内存,而不会直接操作主内存。如果线程对变量的操作没有刷写会主内存的话,仅仅改变了自己的工作内存的变量的副本,那么对于其他线程来说是不可见的。而如果另一个变量没有读取主内存中的新的值,而是使用旧的值的话,同样的也可以列为不可见。

    对于jvm来说,主内存是所有线程共享的java堆,而工作内存中的共享变量的副本是从主内存拷贝过去的,是线程私有的局部变量,位于java栈中。

    那么我们怎么知道什么时候工作内存的变量会刷写到主内存当中呢?

    这就涉及到java的happens-before关系了。

    在JMM中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。

    这个人的博客写的不错:http://ifeve.com/easy-happens-before/。

    简单来说,只要满足了happens-before关系,那么他们就是可见的。

    例如:

    线程A中执行i=1,线程B中执行j=i。如果线程A的操作和线程B的操作满足happens-before关系,那么j就一定等于1,否则j的值就是不确定的。

    happens-before关系如下:

    1. 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;

    2. 锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作;

    3. volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作;

    4. 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;

    5. 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;

    6. 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;

    7. 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;

    8. 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始;

    从上面的happens-before规则,显然,一般只需要使用volatile关键字,或者使用锁的机制,就能实现内存的可见性了。

    3.有序性

    有序性是指程序在执行的时候,程序的代码执行顺序和语句的顺序是一致的。

    为什么会出现不一致的情况呢?

    这是由于重排序的缘故。

    在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。

    举个例子:

    线程A:

    context = loadContext();    
    inited = true;    

    线程B:

    while(!inited ){
     sleep
    }
    doSomethingwithconfig(context);

    如果线程A发生了重排序:

    inited = true;    
    context = loadContext(); 

    那么线程B就会拿到一个未初始化的content去配置,从而引起错误。

    因为这个重排序对于线程A来说是不会影响线程A的正确性的,而如果loadContext()方法被阻塞了,为了增加Cpu的利用率,这个重排序是可能的。

    如果要防止重排序,需要使用volatile关键字,volatile关键字可以保证变量的操作是不会被重排序的。

    END

    看完本文有收获?请转发分享给更多人。

    关注「Java小组」,做顶尖程序员!

    4a3c99d0bddae9f5c1488af77926d8fd.png

    我知道你 “在看ca350155920566a1e96d0ce9fd3187b4.gif

    展开全文
  • 对这个问题,好多人可能第一反应就是使用syschronized关键字,诚然应用这个关键字可以解决问题(仍是有条件线程安全的且低效的),但是在无意中看java源码时,看到了另一种更高效的方式—采用lock的方式。...

    对这个问题,好多人可能第一反应就是使用syschronized关键字,诚然应用这个关键字可以解决问题(仍是有条件线程安全的且低效的),

    贴上Collections.synchronizedMap(new TreeMap<>()) 源码:

      public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
            return new SynchronizedMap<>(m);
        }
    
        /**
         * @serial include
         */
        private static class SynchronizedMap<K,V>
            implements Map<K,V>, Serializable {
            private static final long serialVersionUID = 1978198479659022715L;
    
            private final Map<K,V> m;     // Backing Map
            final Object      mutex;        // Object on which to synchronize
    
            SynchronizedMap(Map<K,V> m) {
                this.m = Objects.requireNonNull(m);
                mutex = this;
            }
    
            SynchronizedMap(Map<K,V> m, Object mutex) {
                this.m = m;
                this.mutex = mutex;
            }
    
            public int size() {
                synchronized (mutex) {return m.size();}
            }
            public boolean isEmpty() {
                synchronized (mutex) {return m.isEmpty();}
            }
            public boolean containsKey(Object key) {
                synchronized (mutex) {return m.containsKey(key);}
            }
            public boolean containsValue(Object value) {
                synchronized (mutex) {return m.containsValue(value);}
            }
            public V get(Object key) {
                synchronized (mutex) {return m.get(key);}
            }
    
            public V put(K key, V value) {
                synchronized (mutex) {return m.put(key, value);}
            }


    通过最后两行代码,可以看到Collections.synchronizedMap的线程安全实质上是在get,put方法加上了独占锁,不仅put存的时候加锁,取得时候也加了锁,所以性能比较差。


    但是在无意中看java源码时,看到了另一种更高效的方式—采用lock的方式,使用读写锁。

    在ReentrantReadWriteLock的源码注释中,作者写了这样一段代码:

    class RWDictionary {
    
         private final Map<String, Data>  m = new TreeMap<String, Data>();
    
         private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    
         private final Lock r = rwl.readLock();
    
         private final Lock w = rwl.writeLock();
    
     
    
         public Data get(String key) {
    
             r.lock(); try { return m.get(key); } finally { r.unlock(); }
    
         }
    
         public String[] allKeys() {
    
             r.lock(); try { return m.keySet().toArray(); } finally { r.unlock(); }
    
         }
    
         public Data put(String key, Data value) {
    
             w.lock(); try { return m.put(key, value); } finally { w.unlock(); }
    
         }
    
         public void clear() {
    
             w.lock(); try { m.clear(); } finally { w.unlock(); }
    
         }
    
      }


    这段代码同样实现了对TreeMap本来非线程安全的类,包装成了一个线程安全的类,且不存在Collections.SynchronizedMap的put_if_absent问题。


    ref:

    https://www.cnblogs.com/weiwelcome0/archive/2012/05/25/2518558.html

    展开全文
  • 线程安全线程安全CollectionVectorArrayList、LinkedListHashSet、TreeSetMapHashTableHashMap、TreeMap字符串StringBufferStringBuilder一、ArrayList和vector区别Vector和ArrayList间唯一的区别就是Vector每个...

    线程安全

    非线程安全

    Collection

    Vector

    ArrayList、LinkedList

    HashSet、TreeSet

    Map

    HashTable

    HashMap、TreeMap

    字符串

    StringBuffer

    StringBuilder

    一、ArrayList和vector区别

    Vector和ArrayList间唯一的区别就是Vector每个方法都自带同步机制。

    例:比如我要往集合里面加一个元素,又要保证多个线程不会同时调用同一个对象的add()方法,ArrayList里面就要这样写:

    ArrayList list = new ArrayList<>();synchronized(list) {

    list.add("233");

    }

    而Vector里面只要这样写就行了:

    Vector list = new Vector<>();

    list.add("233");

    因为ArrayList的add方法是这样定义的:

    public booleanadd(E e) {

    ensureCapacityInternal(size+ 1); //Increments modCount!!

    elementData[size++] =e;return true;

    }

    而Vector的add方法是这样定义的:

    public synchronizedbooleanadd(E e) {

    modCount++;

    ensureCapacityHelper(elementCount+ 1);

    elementData[elementCount++] =e;return true;

    }

    二、HashTable、HashMap、HashSet:

    HashTable和HashMap采用的存储机制是一样的,不同的是:

    1、HashMap:

    a. 非线程安全;

    b. 采用数组方式存储key-value构成的Entry对象,key允许为null,无容量限制;

    c. 遍历使用的是Iterator迭代器;

    2、HashTable:

    a. 线程安全; (对方法加上synchronized)

    b. 无论是key还是value都不允许有null值的存在;在HashTable中调用Put方法时,如果key为null,直接抛出NullPointerException异常;

    c. 遍历使用的是Enumeration列举;

    3、HashSet:

    a. 非线程安全

    b. 底层通过HashMap实现,无容量限制;

    c. 不保证数据的有序;

    在HashSet中,元素都存到HashMap键值对的Key上面,而Value是统一的值private static final Object PRESENT = new Object();,(定义一个虚拟的Object对象作为HashMap的value,将此对象定义为static final。)

    HashSet的add(E e)底层实现调用hashmap的put(E e),将该元素作为key放入HashMap。

    由于HashMap的put()方法添加key-value对时,当新放入HashMap的Entry中key与集合中原有Entry的key相同(hashCode()返回值相等,通过equals比较也返回true), 新添加的Entry的value会将覆盖原来Entry的value,但key不会有任何改变, 因此如果向HashSet中添加一个已经存在的元素时,新添加的集合元素将不会被放入HashMap中, 原来的元素也不会有任何改变,这也就满足了Set中元素不重复的特性。

    三、TreeSet、TreeMap:

    TreeSet和TreeMap都是完全基于Map来实现的,并且都不支持get(index)来获取指定位置的元素,需要遍历来获取。另外,TreeSet还提供了一些排序方面的支持,例如传入Comparator实现、descendingSet以及descendingIterator等。

    1、TreeSet:

    a. 非线程安全

    b. 底层基于TreeMap实现,支持排序;

    2、TreeMap:

    a. 非线程安全;

    b. 典型的基于红黑树的Map实现,因此它要求一定要有key比较的方法,要么传入Comparator比较器实现,要么key对象实现Comparator接口;

    与hashmap相比,treemap内部的元素都是排序的,当需要查找某些元素以及顺序输出元素的时候占优势。因此,TreeMap是一个内部元素排序版的HashMap

    四、StringBuffer和StringBulider:

    StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串。

    它们是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,不像String一样创建一些对象进行操作,所以速度就快了;

    1、在执行速度方面的比较:StringBuilder > StringBuffer ;

    2、StringBuilder:非线程安全;

    3、StringBuffer:线程安全; (对方法加上synchronized)

    对于String、StringBuffer和StringBulider三者使用的总结:

    1.如果要操作少量的数据:String

    2.单线程操作字符串缓冲区下操作大量数据:StringBuilder

    3.多线程操作字符串缓冲区下操作大量数据:StringBuffer

    非线程安全!=不安全

    虽然ArrayList是线程不安全的,但不代表在多线程下不能使用ArrayList,只能使用Vector。

    非线程安全并不是多线程环境下就不能使用。线程安全问题在于:多线程操作同一个对象。注意是同一个对象。比如最上面那个模拟,就是在主线程中new的一个ArrayList然后多个线程操作同一个ArrayList对象。

    如果是每个线程中new一个ArrayList,而这个ArrayList只在这一个线程中使用,那么肯定是没问题的。

    展开全文
  • 1.Hashtable是一个线程安全的Map实现,但HashMap是线程不安全的实现,所以HashMap比Hashtable的性能好一些;但如果有多个线程访问同一个Map对象时,使用Hashtable实现类会更好。 2.Hashtable不允许使用null作为...
  • 线程安全(Thread-safe)的集合对象: Vector 线程安全: HashTable 线程安全: StringBuffer 线程安全: 非线程安全的集合对象: ArrayList : LinkedList: HashMap: HashSet: TreeMap: TreeSet: StringBulider...
  • 作者:a60782885blog.csdn.net/a60782885/article/details/77803757注,本篇只是解析基本概念,用作面试应答,非深入对于Java并发编程,一般来说有以下的关注点:线程安全性,正确性。线程的活跃性(死锁,活锁)性能...
  • 目录一、ArrayList和vector区别二、HashTable...java中线程安全和非线程安全的集合 一、ArrayList和vector区别 Vector和ArrayList间唯一的区别就是Vector每个方法都自带同步机制。 例:比如我要往集合里面加一个元素,
  • 线程安全线程安全 Collection Vector ArrayList、LinkedList HashSet、TreeSet Map HashTable HashMap、TreeMap 字符串 StringBuff...
  • TreeMap使用和底层原理和实现Comparable接口 ,HashMap和TreeMap的区别:HashMap线程不安全,效率高(允许key为null或者value为null),TreeMap线程安全,效率低(不允许key为null或者value为null) package ...
  • mapmap基本操作,hashmap与hashtable区别,hashmap需要注意的点转载,hashmap,linkedmap,treemap一些总结hashmap和treemap区别 map基本操作,hashmap与hashtable区别,hashmap需要注意的点 map存储的是k-v键值对...
  • TreeMap

    2019-12-01 20:03:28
    TreeMap 是一个有序的key-value集合,它是通过红黑树实现的。... TreeMap是非线程安全的。 它的iterator 方法返回的迭代器是fail-fast的。 TreeMap类声明: public class TreeMap<K,V>...
  • 我们都知道,Java中常用的集合框架中的实现类HashSet、TreeSet、ArrayList、ArrayDeque、LinkedList、HashMap、...Collections提供了synchronizedXxx()方法来帮助其实现线程安全。下面给出代码演示:import ja...
  • 下面哪些具体实现类可以用于存储键,值对,并且方法调用提供了基本的多线程安全支持:(A E) java.util.ConcurrentHashMap java.util.Map java.util.TreeMap java.util.SortMap java.util.Hashtable java.util...
  • Java集合多线程安全

    2020-07-17 20:35:38
    一、线程安全 线程不安全集合: ArrayList LinkedList HashMap HashSet TreeMap TreeSet StringBulider 线程安全集合: Vector HashTable Properties 二、集合线程安全与解决方案 2.1ArrayList线程安全问题 ...
  • 1.HashSet 非线程安全【1】2.TreeSet 非线程安全 【2】3.LinkedHashSet 非线程安全 【3】4.ArrayList 非线程安全 【4】5.LinkedList 非线程安全 【5】6.HashMap 非线程安全 【6】7.TreeMap线程安全 【7】8....
  • Java集合Map1. Map比较2. 遍历map ...线程安全? 安全 不安全 安全 不安全 不安全 可存null 都不可以 允许一个null的key,多个null的value key顺序 无序 无序 无序 保留存入顺序 对key按指定...
  • TreeMap的底层结构是红黑树,特点是有序(默认升序排序)不可重复,根据key实现去重和排序,如果key存储的是自定义引用类型数据,需要实现内部比较器或外部比较器。 代码: import java.util.Objects; import java....
  • Java 集合线程安全

    2019-09-20 09:00:03
    线程不安全的的集合有(HashSet,TreeSet,ArrayList,ArrayDeque,LinkedList,HashMap,...线程安全的集合有(Vector,HashTable); Java给你的保证的线程安全,是说它的方法是执行是排它的,而不是对这个对象本身的...
  • java 的容器线程安全

    2012-04-25 15:53:45
    java 的容器线程安全 1.HashSet 非线程安全【1】   2.TreeSet 非线程安全 【2】 3.LinkedHashSet 非线程安全 【3】 4.ArrayList 非线程安全 ...7.TreeMap线程安全 【7】 8.LinkedHashMap 非线程安全 【8】
  • TreeMap 是否线程安全 首先回答,线程不安全 import java.util.TreeMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,014
精华内容 405
关键字:

treemap线程安全