目录
1.加锁
2.锁死和重入
3.线程安全的类
4.volatile
1.加锁
当两个线程同时对一个对象进行加锁的时候,会产生竞争
2.锁死和重入
如果一个线程对一个对象加了一次锁,在加一次出现死锁,就是不可重入,否则就是可重入
锁死:对同一个锁再加锁出现的死循环
实际上开发JVM的工程师对加两把锁出现的情况进行了优化,实现了可重复锁
可重复锁:当加第一把锁的时候,加锁成功,记录谁加的锁,加锁次数:1
第二次再加锁的时候,是个假加锁,只是把加锁次数自增1,后续解锁的时候把加锁次数-1,直到为0就真的解锁了
可重复锁:大大提高了开发效率(防止死锁),降低了运行效率,由于要记录谁加的锁和加锁的次数
死锁的原因:
1.互斥性:线程占据锁了之后,其他线程不能占据
2.不可抢占:线程占据锁了之后,其他线程不能抢夺
3.请求和保持:一个线程占据了多把锁之后,除非主动释放锁,否则这些锁一直存在
4.环形死锁问题
约定好加锁的顺序可以解决哲学家吃饭导致的环形死锁问题.
3.线程安全的类
Sting
StringBuffer
ConcurrentHashMap
String线程安全的原因是String是不可变对象,无法在多个线程中修改同一个String的值
不可变对象和常量,final关系
final表示三种不能被修改继承重写
加锁就会线程安全,剩余的大部分基本上都是不安全的类
4.volatile
作用是禁止编译器进行优化,保证内存可见性.
因为这个属性可能是不稳定的.
cpu和内存之间还存在缓存(cache),比如说我台式电脑12400f的缓存时24M,因为cpu从内存取数据由于内存拖后腿,太慢了,所以cpu决定把内存里面的东西先放到缓存上,再让cpu读取数据.提高了cpu的速度,现在典型的cpu都是三级缓存
volatile 只是保证内存可见性,并不保证原子性
只是处理一个大量线程读,一个线程写的情况
synchronized 保证原子性和内存可见性