多线程不安全的底层原因以及两种加锁方式的区别
如何保证多线程的安全运行
1.线程的安全性问题体现在:
- 原子性:一个或者多个操作在 CPU 执行的过程中不被中断的特性
- 可见性:一个线程对共享变量的修改,另外一个线程能够立刻看到
- 有序性:程序执行的顺序按照代码的先后顺序执行
2.导致原因:
- 缓存导致的可见性问题
- 线程切换带来的原子性问题
- 编译优化带来的有序性问题
3.解决办法:
- JDK Atomic 开头的原子类、synchronized、Lock,可以解决原子性问题
- synchronized、volatile、Lock,可以解决可见性问题
- Happens-Before 规则可以解决有序性问题,JVM对程序运行设定的一些规则。
两种加锁方式的区别
1.这里的两种加锁方式分别指的是synchronized关键字和Lock类。
2.这两种方式的底层实现可以看:
3.synchronized和Lock的区别:
- 实现层面不一样。synchronized 是 Java 关键字,JVM 层面 实现加锁和释放锁;Lock 是一个接口,在代码层面实现加锁和释放锁,(CAS乐观锁比synchronized更底层,是CPU原语,属于操作系统层面的)
- 是否自动释放锁。synchronized 在线程代码执行完或出现异常时自动释放锁;Lock 不会自动释放锁,需要再 finally {} 代码块显式地中释放锁
- 是否一直等待。synchronized 会导致线程拿不到锁一直等待;Lock 可以设置尝试获取锁或者获取锁失败一定时间超时
- 获取锁成功是否可知。synchronized 无法得知是否获取锁成功;Lock 可以通过 tryLock 获得加锁是否成功
- 功能复杂性。synchronized 加锁可重入、不可中断、非公平;Lock 可重入、可判断、可公平和不公平、细分读写锁提高效率
【Java 面试那点事】
这里致力于分享 Java 面试路上的各种知识,无论是技术还是经验,你需要的这里都有!
这里可以让你【快速了解 Java 相关知识】,并且【短时间在面试方面有跨越式提升】
面试路上,你不孤单!