当前位置:   article > 正文

Java中的多线程安全问题_说说java并发运行中的一些安全问题

说说java并发运行中的一些安全问题

目录

一、什么是线程安全?

二、线程不安全的原因

2.1 从底层剖析count++的操作

2.2 线程不安全的原因总结

2.3 JVM内存模型(JMM)

三、synchronized 关键字-监视器锁monitor lock

 3.1 如何加锁(Synchronized用法和特性)

3.1.1. 独占性

3.1.2 可重入性

四、Java 标准库中的线程安全类

五、volatile关键字

5.1 volatile可以保证内存可见性

5.2 volatile不可以保证原子性


一、什么是线程安全?

简单的理解:如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的。

观察一下代码:使用两个线程,每个线程都对这个 Counter进行5w次自增,预计是结果为10w。

  1. /**
  2. * Created with IntelliJ IDEA.
  3. * Description:
  4. * User: 86136
  5. * Date: 2023-01-12
  6. * Time: 20:50
  7. */
  8. class Counter {
  9. public int count = 0;
  10. public void increase() {
  11. count++;
  12. }
  13. }
  14. public class Demo13 {
  15. static Counter counter = new Counter();
  16. public static void main(String[] args) throws InterruptedException {
  17. //使用两个线程,每个线程都对这个 Counter进行5w次自增
  18. //预计是结果为10w
  19. Thread t1 = new Thread(() -> {
  20. for (int i = 0; i < 5_0000; i++) {
  21. counter.increase();
  22. }
  23. });
  24. Thread t2 = new Thread(() -> {
  25. for (int i = 0; i < 5_0000; i++) {
  26. counter.increase();
  27. }
  28. });
  29. t1.start();
  30. t2.start();
  31. t1.join();
  32. t2.join();
  33. System.out.println(counter.count);
  34. }
  35. }

运行结果:

二、线程不安全的原因

上面我们使用了多线程运行了一个程序,想让这个变量从0自增到10w次,但是最终实际结果比我们预期的结果要小,这是线程调度顺序的随机性导致的,造成了线程间自增的指令集交叉,导致本来需要自增两次但值只自增了一次的情况。所以得到的结果偏小。

2.1 从底层剖析count++的操作

count++ 操作,在底层其实是被分为三条指令在CPU上进行执行的

  1. 把内存的数据读取到CPU的寄存器上(load)
  2. 把CPU的寄存器中的值,进行+1(add)
  3. 把寄存器中的值,写回到内存中(save)

这里简单的描述几种情况,初始条件:初始值为1,对其进行两次自增。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/650129
推荐阅读
相关标签