首先什么是线程安全?
原子性
这一点,跟数据库事务的原子性概念差不多,即一个操作(有可能包含有多个子操作)要么全部执行(生效),要么全部都不执行(都不生效)。
一致性(可见性)
可见性是指,当多个线程并发访问共享变量时,一个线程对共享变量的修改,其它线程能够立即看到。可见性问题是好多人忽略或者理解错误的一点。
顺序性
顺序性指的是,程序执行的顺序按照代码的先后顺序执行。
ConcurrentXXX系列
用ConcurrentHashMap作为例子来讲。
1.8之后,ConcurrentHashMap的数据结构是Node数组+链表/红黑树。
写安全
如果Node结点是空的,直接CAS写入
如果Node结点不是空的,则synchronized对结点加锁,添加链表结点or红黑树结点
读安全
使用Volatile关键字修饰。Volatile关键字可以保证变量的可见性。ps:volatile只能保证读安全,写是不安全的
CopyOnWriteXXX系列
写写阻塞,其他不阻塞
写安全
顾名思义,写的时候是直接把变量复制一份出来,在复制出来的这一份上面改,改完了把原来的指针指向复制的这一份。
读安全
天然线程安全。读取操作没有任何同步控制和锁操作,理由就是内部数组 array 不会发生修改,只会被另外一个 array 替换,因此可以保证数据安全
读写锁ReentrantReadWriteLock
读读不互斥、读写互斥、写读互斥、写写互斥
每次只能有一个写线程,但是同时可以有多个线程并发地读数据
ReadWriteLock管理一组锁,一个是只读的锁,一个是写锁。读锁可以在没有写锁的时候被多个线程同时持有(共享),写锁是独占的