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

  • 委托是创建线程安全类的一个最有效的策略, 只需让现有的线程安全类管理所有的状态即可

  • 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、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 7,042评论 0 4
  • 进程和线程 进程 所有运行中的任务通常对应一个进程,当一个程序进入内存运行时,即变成一个进程.进程是处于运行过程中...
    胜浩_ae28阅读 10,532评论 0 23
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,443评论 11 349
  • Java8张图 11、字符串不变性 12、equals()方法、hashCode()方法的区别 13、...
    Miley_MOJIE阅读 9,120评论 0 11
  • 说到撒谎,小朋友都知道,撒谎是不对的。但是,我这次撒谎却包含着对妈妈的浓浓的爱。 ...
    是滢滢呀阅读 1,911评论 0 3