Java并发编程 - 发布对象 JUC笔记

安全的发布对象

  • 在静态初始化函数中初始化一个对象引用
  • 将对象的引用保存到volatile类型域或者AtomoicReference对象中
  • 将对象的引用保存到某个正确构造对象的final类型域中
  • 将对象的引用保存到一个由锁保护的域中

不可变对象需要满足的条件

  • 对象创建以后其状态就不能修改
  • 对象所有域都是final类型
  • 对象是正确创建的

不可变对象

  • final
  • Collections.unmodifiableXXX:Colleciton,list,set,map....
  • Guava:ImmutablaeXXX:Collection,list,map...

线程封闭

  • Ad-hoc线程封闭:程序控制实现,最糟糕
  • 堆栈封闭:局部变量,无并发问题
  • ThreadLocal 线程封闭:最好的封闭方法

线程安全类与线程不安全类

  • SimpleDateFormat线程不安全,JodaTime线程安全。

同步容器

  • Vector,Stack,HashTable(key,value不能为空)
  • Collections.synchronizedXXX(List,Set,Map)
  • 在遍历中需要删除容器中的元素,不要用迭代器或者foreach,要用for。最好是在遍历结束后再进行删除操作。否则也是线程不安全的。

并发容器

  • CopyOnWriteArrayList,CopyOnWriteArraySet,CopyOnWriteArraySkipListSet
  • ConcurrentHashMap,ConcurrentSkipListMap (跳表,用空间换时间)

ReentrantLock

  • 可指定是公平锁还是非公平锁。
  • 提供了一个Condition类,可以分组唤醒需要唤醒的线程。
  • 提供能够中断等待锁的线程的机制,lock.lockInterruptibly()。

四种锁的特性

  • synchronized同步锁
    1. synchronized属于悲观锁,直接对区域或者对象加锁,性能稳定,可以使用大部分场景。
  • ReentrantLock可重入锁(Lock接口)
    1. 相对于synchronized更加灵活,可以控制加锁和放锁的位置
    2. 可以使用Condition来操作线程,进行线程之间的通信
    3. 核心类AbstractQueuedSynchronizer,通过构造一个基于阻塞的CLH队列容纳所有的阻塞线程,而对该队列的操作均通过Lock-Free(CAS)操作,但对已经获得锁的线程而言,ReentrantLock实现了偏向锁的功能。
  • ReentrantReadWriteLock可重入读写锁(ReadWriteLock接口)
    1. 相对于ReentrantLock,对于大量的读操作,读和读之间不会加锁,只有存在写时才会加锁,但是这个锁是悲观锁。
    2. ReentrantReadWriteLock实现了读写锁的功能ReentrantReadWriteLock是ReadWriteLock接口的实现类。ReadWriteLock接口的核心方法是readLock(),writeLock()。
    3. 实现了并发读、互斥写。但读锁会阻塞写锁,是悲观锁的策略。
  • StampedLock戳锁
    1. ReentrantReadWriteLock虽然解决了大量读取的效率问题,但是,由于实现的是悲观锁,当读取很多时,读取和读取之间又没有锁,写操作将无法竞争到锁,就会导致写线程饥饿。所以就需要对读取进行乐观锁处理。
    2. StampedLock加入了乐观读锁,不会排斥写入。
    3. 当并发量大且读远大于写的情况下最快的是StampedLock锁。

BlockingQueue

死锁

  • 互斥条件
  • 请求与保持条件
  • 不剥夺条件
  • 循环等待条件

多线程并发最佳实践

  • 宁可使用同步也不使用线程的wait和notify。
  • 使用BlockingQueue实现生产-消费模式。
  • 使用并发集合而不是加了锁的同步集合。
  • 使用Semaphore创建有界的访问。
  • 宁可使用同步代码块,也不使用同步的方法。
  • 避免使用静态变量。

猜你喜欢

转载自blog.csdn.net/weixin_34049032/article/details/87560220