扫一扫
关注公众号
保证线程安全本质上是保证线程同步,实际上就是线程间通信问题,线程通信常见方式有信号量、管道、共享内存、消息队列、socket,java线程通信主要使用共享内存,那么首先需要关注的是可见性、有序性、原子性问题,然后就是活跃性问题和性能问题。
特性 | volatile关键字 | synchronized关键字 | Lock接口 | Atomic变量 |
---|---|---|---|---|
原子性 | 无法保障 | 可以保障 | 可以保障 | 可以保障 |
可见性 | 可以保障 | 可以保障 | 可以保障 | 可以保障 |
有序性 | 一定程度保障 | 可以保障 | 可以保障 | 无法保障 |
前面一个操作的结果对后续操作是可见的。
争夺资源而造成互相等待的情况。可以通过资源一次性分配、可剥夺资源、资源有序分配法进行预防,银行家算法进行避免,在分配资源前先看清楚,分配后不会造成死锁就分配,否则不分配
线程虽然没有阻塞但是仍然会存在执行不下去的情况,比如相互谦让,处理办法是相撞后各自等待一个随机值。
线程无法访问到所需资源而无法继续执行下去,可以通过保证资源充足或者公平地分配资源(先来后到的公平锁),防止持有锁的线程长时间执行。
锁的过度使用可能导致串行化的范围变大,造成吞吐量、延迟、并发量变差,可以使用下面的两种方案解决
Copy-on-write最常见的就是iterator的修改,使用了CopyOnWriteArrayList,在操作新元素时不直接操作原容器,而是先复制一个快照,对这个快照进行操作,在操作结束后再将原容器的引用指向新引用
concurrentHashMap将内部分成多个segment数组,segment通过继承ReentrantLock加锁。segment里面则是hashEntry数组,hash值相同的条目以链表的形式存放,当数目达到一定时采用红黑树存放。另外hashEntry内部使用volatile的value字段来保证可见性