Java线程安全基础知识

版权声明:原创作品,转贴请注明出处! https://blog.csdn.net/sa19861211/article/details/90313525

1. synchronized

JMM关于synchronized的两条规定:

  1. 线程解锁前,必须把共享变量的最新值刷新到主内存中
  2. 线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中
    重新获取最新的值(注意:加锁与解锁需要是同一把锁)
    通过以上两点,可以看到synchronized能够实现可见性。同时,由于synchronized具有同步锁,所以它也具有原子性。
    结论:synchronized既解决了可见性,又解决了原子性

2. Lock

2.1 ReentrantLock重入锁
在需要进行同步的代码前加锁,但不要忘记在最后一定要释放锁,不然会造成锁永远无法释放,造成其它线程永远进不来。
2.2 ReentrantReadWriteLock
ReentrantReadWriteLock其核心就是实现读写分离的锁,在高并发访问下,尤其是读多写少的情况下,性能要远高于重入锁。
其本质是分成两个锁,读写和写锁。在读锁下多个线程可以并发进行访问,但是在写锁的时候,只能一个一个地顺序访问。
规则:读读共享,读写互斥,写写互斥。

3. volatile

volatile关键字的作用就是强制线程到主内存(共享内存)里去读取变量,而不是到线程的工作内存里读取。从来实现了多个线程间的变量可见,也就是满足了线程安全的可见性。
结论:volatile只解决了可见性,没有解决原子性。

4. Atomic原子类

例如:AtomicInteger,AtomicLong …
支持原子性操作,但是只保证本身方法的原子性,并不保证多次操作的原子性。

5. ThreadLocal

线程局部变量,是一种多线程间并发访问变量的解决方案。
与其synchronized等加锁的方式不同,ThreadLocal完全不提供锁,而是使用以空间换时间的手段,为每个线程提供变量的独立副本,以保障线程安全。
从性能上说,ThreadLocal不具有绝对的优势。在并发不是很高的情况下,加锁的性能会更好,但作为一套与锁完全无关的线程安全解决方案,在高并发量或者竞争激烈的场景,使用ThreadLocal可以在一定程度上减少锁竞争。

6. 锁优化

锁优化应该遵循以下几条原则:

  • 尽量使用无锁操作,例如:原子操作(Atomic*系列类)和volatile关键字。
  • 减少锁的持有时间
  • 减小锁的粒度
  • 锁的分离(读写锁)
  • 避免死锁

猜你喜欢

转载自blog.csdn.net/sa19861211/article/details/90313525
今日推荐