高并发网课的笔记(二)

CH05

  • 对象发布:
    • 发布: 使一个对象能够被当前范围之外的代码所使用
    • 对象逸出: 当一个对象还没有构造完成就被其他线程所见
  • 安全发布对象的四种方法:
    1. 在静态初始化函数中初始化一个对象引用
    2. 将对象的引用保存到volatile类型域或者AtomicReference对象中
    3. 将对象的引用保存到某个正确构造对象的final类型域中
    4. 将对象的引用保存到一个由锁保护的域中
  • 懒汉式单例线程不安全的坏处: 如果初始化中有很多操作, 则重复的实例化会产生错误的状态. 要改成双重检测同步锁单例(这还不是线程安全的, 要考虑对象初始化和引用赋值因指令重排而顺序颠倒, 在第二次判断前可能被切换).为了解决该问题, 需要将引用变量变成volatile来禁止指令重排(volatile的使用场景)
  • 饿汉式的坏处: 首先饿汉式是线程安全的, 但是当初始化中有很多操作时, 会拖慢类加载的速度, 且可能造成资源浪费
  • 一定要注意静态块和静态方法的执行顺序(类加载时顺序执行)
  • 使用枚举来做单例是最安全高效的, 同时拥有饿汉式和懒汉式的特性. 原理是在枚举中我们明确了构造方法限制为私有,在我们访问枚举实例时会执行构造方法,同时每个枚举实例都是static final类型的, 也就表明只能被实例化一次. 在调用构造方法时, 我们的单例被实例化. 也就是说,因为enum中的实例被保证只会被实例化一次, 所以我们的INSTANCE也被保证实例化一次.

CH06

  • 不可变对象
    • 需要满足的条件:
      1. 对象创建以后其状态就不能修改
      2. 对象所有域都是final类型
      3. 对象是正确创建的(在对象创建期间, this引用没有逸出)
    • 实现方式(多参考String类型):
      1. 声明为final类
      2. 将成员变量声明为私有的
      3. 不设置set方法, get方法返回对象的深度拷贝
  • Integer等包装类和String 一旦声明成final后被修改, 编译时就会出现错误
  • 引用类型用final修饰只是保证引用(或者说地址)不变, 但引用指向的对象还是存在被修改的风险
  • Java有提供不可变的集合类型: Collections.unmodifiableXXX : Collection、List、Set等等, 但是编译可以通过, 只是会抛出异常
    • Guava包也有提供 ImmutableXXX…
  • 线程封闭: 把变量限制在当前线程里
    • 方法:
      1. Ad-hoc: 程序员自己控制, 最糟糕的方式
      2. 堆栈封闭: 局部变量, 无并发问题
      3. ThreadLocal类: 用Map来维护不同线程. 经典应用: JDBC的连接成管理的Connection对象
  • 常见类
    • StringBuilder: 线程不安全, 快(同时有多个线程), 在线程封闭的场景下尽可能用StringBuilder
    • StringBuffer: 线程安全, 每个方法都有synchronized, 慢
    • DateformatExample: 不是线程安全的, 正确写法是在方法里每次生成新对象来使用
    • DateTimeFormmatter: 线程安全的, 在joda-time的包中, 实际开发中更推荐
    • ArrayList、HashSet、HashMap等Collections: 线程不安全的
  • 线程不安全类的写法: 先检查后判断: if(condition(a)){handle(a);}, 原因是判断和操作两个操作不是原子操作, 需要用synchronized或CAS解决
  • 同步容器:接近线程安全
    • List -> Vector(使用它时可能还需要额外的同步措施, 因为它的size()方法没有synchronized), Stack, 都用synchronized 方法
    • Map -> HashTable(key, value不能为null), 线程同步的
    • Collections.synchronizedXXX(List、Set、Map)
  • 尽量不要在迭代或迭代器里面做remove()操作, 在遍历时标记, 完了之后再remove()
  • 并发容器(JUC): 读写分离和最终一致性原理
    • CopyOnWriteArrayList: 新数组被修改时, 拷贝旧的, 分配新的再重新引用;整个操作都在锁中完成;适合读多改少的场景
    • CopyOnWriteArraySet(对应HashSet)、ConcurrentSkipListSet(对应TreeSet): 特性同上,前者基于List, 后者基于Map
    • CopyOnWriteHashMap(对应HashMap)、ConcurrentSkipListMap(对应TreeMap)
  • 安全共享对象策略:
    • 线程限制: 对象由线程独占
    • 共享只读: 提供多个线程并发访问, 但是任何线程都不能修改它
    • 线程安全对象: 对象内部就保证线程安全的
    • 被守护对象: 被守护对象只能通过获取特定的锁来访问

多线程笔记

  1. 如何理解notify/notifyAll的作用? 首先理解有等待池(线程提出wait之后到这里来)和锁池(没争到锁的线程被阻塞到这里,可以竞争锁), notify/notifyAll可以看作是将等待迟里的线程搬到锁池
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值