安全的发布对象
- 在静态初始化函数中初始化一个对象引用
- 将对象的引用保存到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同步锁
- synchronized属于悲观锁,直接对区域或者对象加锁,性能稳定,可以使用大部分场景。
- ReentrantLock可重入锁(Lock接口)
- 相对于synchronized更加灵活,可以控制加锁和放锁的位置
- 可以使用Condition来操作线程,进行线程之间的通信
- 核心类AbstractQueuedSynchronizer,通过构造一个基于阻塞的CLH队列容纳所有的阻塞线程,而对该队列的操作均通过Lock-Free(CAS)操作,但对已经获得锁的线程而言,ReentrantLock实现了偏向锁的功能。
- ReentrantReadWriteLock可重入读写锁(ReadWriteLock接口)
- 相对于ReentrantLock,对于大量的读操作,读和读之间不会加锁,只有存在写时才会加锁,但是这个锁是悲观锁。
- ReentrantReadWriteLock实现了读写锁的功能ReentrantReadWriteLock是ReadWriteLock接口的实现类。ReadWriteLock接口的核心方法是readLock(),writeLock()。
- 实现了并发读、互斥写。但读锁会阻塞写锁,是悲观锁的策略。
- StampedLock戳锁
- ReentrantReadWriteLock虽然解决了大量读取的效率问题,但是,由于实现的是悲观锁,当读取很多时,读取和读取之间又没有锁,写操作将无法竞争到锁,就会导致写线程饥饿。所以就需要对读取进行乐观锁处理。
- StampedLock加入了乐观读锁,不会排斥写入。
- 当并发量大且读远大于写的情况下最快的是StampedLock锁。
BlockingQueue
- ArrayBlockingQueue
- DelayQueue
- LinkedBlockingQueue
- ProrityBlockingQueue
- SynchronousQueue
- https://www.cnblogs.com/WangHaiMing/p/8798709.html
死锁
- 互斥条件
- 请求与保持条件
- 不剥夺条件
- 循环等待条件
多线程并发最佳实践
- 宁可使用同步也不使用线程的wait和notify。
- 使用BlockingQueue实现生产-消费模式。
- 使用并发集合而不是加了锁的同步集合。
- 使用Semaphore创建有界的访问。
- 宁可使用同步代码块,也不使用同步的方法。
- 避免使用静态变量。
网友评论