美文网首页
1_基础知识_chapter05_基础构建模块_1_同步容器类

1_基础知识_chapter05_基础构建模块_1_同步容器类

作者: 米都都 | 来源:发表于2019-01-22 17:54 被阅读0次
    • 委托是创建线程安全类的一个最有效的策略, 只需让现有的线程安全类管理所有的状态即可

    • Collections.synchronizedXXX是一些同步容器类, 这些类的实现方式是将它们的状态封装起来, 并且对每个公有方法都进行同步

    • 同步容器类包括 Vector, HashTable, Collections.synchronizedXXX

    • 同步容器类的问题

      (1) 同步容器类是线程安全的, 但是在执行复合操作时仍需要客户端加锁

      复合操作有:

      迭代

      跳转(根据指定顺序找到当前元素的下一个元素)

      条件运算(若容器中不存在某个元素, 则添加这个元素)

    示例
    
        public class SafeVectorHelpers {
        
            public static Object getLast(Vector list) {
        
                int lastIndex = list.size() - 1;
                return list.get(lastIndex);
            }
    
            public static void deleteLast(Vector list) {
        
                int lastIndex = list.size() - 1;
                list.remove(lastIndex);
            }
        }
    
    当有两个线程分别对同一个Vector容器执行getLast和deleteLast函数时, 一个执行完get(),另一个执行remove就会报错
    
    (2) 为了保证复合操作的线程安全性就要加锁, 此时符合"客户端加锁"的条件:找到同步容器使用了哪一个锁,并对它加锁
    
    • 迭代器的迭代问题

      (1) 无论显式用迭代器迭代还是用for-each语法, 本质都是使用Iterator迭代

      (2) 容器使用了及时失败机制: 当发现容器在迭代过程中被外部更改或其他线程更改时, 报ConcurrentModification异常

      (3) 防止容器报ConcurrentModification异常的手段

      加锁

      先克隆容器, 再在克隆容器上迭代(克隆过程也要加锁)

      两种手段都会使性能下降, 综合考虑各种因素才能比较出两种手段在不同场合下的优劣

      (3) 隐藏迭代器

      很多时候方法内部也使用了迭代, 但是隐藏了起来, 这时不注意的话就有多线程迭代异常的问题

      示例

        public class HiddenIterator {
      
            @GuardedBy("this")
            private final Set<Integer> set = new HashSet<Integer>();
      
            public synchronized void add(Integer i) {
                set.add(i);
            }
      
            public synchronized void remove(Integer i) {
                set.remove(i);
            }
      
            public void addTenThings() {
      
                Random r = new Random();
      
                for (int i = 0; i < 10; i++) {
                    this.add(r.nextInt());
                }
      
                System.out.println(this.set);
            }
        }
      

      这里的addTenThings函数的最后一行System.out.println(this.set)会隐式调用set的迭代器, 将set中的所有元素转换为String, 如果此时其他线程调用了add或remove函数, 就会出现迭代异常

    相关文章

      网友评论

          本文标题:1_基础知识_chapter05_基础构建模块_1_同步容器类

          本文链接:https://www.haomeiwen.com/subject/eqzqjqtx.html