深圳罗湖网站制作公司哪家好/凡科网建站系统源码
文章目录
- 1、上下文切换
- 2、名称解析
下面我们以2个线程对同一个类中同一静态变量做简单自增和自减为例,初步了解线程安全问题。
一个线程对初始值为0的静态变量做自增5000次,另外一个线程对同一静态变量做自减5000次,结果会是我们预想的0吗?
public class ThreadSecurity01 {static int n = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 5000; i++) {n++;}}, "t1");Thread t2 = new Thread(() -> {for (int i = 0; i < 5000; i++) {n--;}}, "t2");t1.start();t2.start();t1.join();t2.join();log.debug("最终结果:{}", n);}
}
多次执行,结果并不是0,而是不可预知的结果,为什么会出现这样的结果呢?下面我们简单介绍下多线程安全问题。
1、上下文切换
问题分析:因为Java对静态变量的自增、自减操作并不是原子性的,下面我们重字节码来分析。
例如对于i++而言(i为静态变量),实际会产生如下的JVM字节码指令:
getstatic i // 获取静态变量的值
iconst_1 // 准备常量1
iadd // 自增
putstatic i // 将修改后的值存入静态变量i
而对应的i–也是类似
getstatic i // 获取静态变量的值
iconst_1 // 准备常量1
isub // 自减
putstatic i // 将修改后的值存入静态变量i
而Java的内存模型,完成静态变量的值的自增,自减要在主存和工作内存之间交换值,图示:
上面是各运行一次自增和自减,结果为-1的情况,为1, 0的情况也是如此。
2、名称解析
-
一个线程运行多个线程是没问题的
-
问题出在多个线程访问共享资源
- 多个线程读共享资源,也是没问题的
- 多个线程对共享资源读写导致线程切换,指令交错,就会出现问题
-
临界区:一段代码块内如果存在对共享资源的多线程读写操作,称该代码块为临界区
-
竞态条件:多个线程在临界区内执行,由于代码的执行序列不同二导致结果无法预测,称之为发生了竞态条件。
想要进一步的理解多线程安全问题产生,需要深入了解Java内存模型、JVM工作原理、操作系统任务调度等等知识, 这一块还没有学到,暂时讲解到这来。有兴趣的可以自行搜索,或者参考一下文章:
参考文章:
-
由java内存模型探讨线程安全的问题
-
想要进一步的理解多线程安全问题产生,需要深入了解Java内存模型、JVM工作原理、操作系统任务调度等等知识, 这一块还没有学到,暂时讲解到这来。有兴趣的可以自行搜索,或者参考一下文章:
参考文章:- 由java内存模型探讨线程安全的问题
- Java内存区域(运行时数据区域)和内存模型(JMM)
下面我讲解线程安全的解决方法之一,互斥同步。