package javabase.src.thread;
public class StaticMethodTest {
private static int a = 0;
public static void main(String[] args) {
new Thread(StaticMethodTest::run, "thread1").start();
new Thread(() -> run2(), "thread2").start();
}
public static void test(int param) throws InterruptedException {
System.out.println("==============="+Thread.currentThread().getName()+"操作之前的a值:"+a+"===================");
// 先让 线程进行操作之前 都能 先拿值(造成线程安全问题)
Thread.sleep(1000);
a += param;
System.out.println("==============="+Thread.currentThread().getName()+"进行加"+param+"操作之后的a值:"+a+"=============");
}
private static void run() {
try {
test(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void run2() {
try {
// 目的 : 等待 其他线程执行完毕后在执行
// 让执行此业务的 线程 先sleep 1秒
Thread.sleep(1000);
test(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果
===============thread1操作之前的a值:0===================
===============thread2操作之前的a值:0===================
===============thread1进行加1操作之后的a值:1=============
===============thread2进行加2操作之后的a值:3=============
结果分析:
通过结果我们很容易看出问题所在
thread1和thread2 进行运算之前获取的值都是 0
thread1:0 + 1 = 1 结果正确
thread2:0 + 2 = 3 结果错误
原理分析 static修饰的属性 在JVM 内存中是存储在 方法区中,全局使用的此属性 只有一份
为了保证两个线程都是 先取值 再运算
使用Thread.sleep(1000);
进入TImed-waitting 状态(线程具体状态及源码解析详见
线程-Thread类源码解析及线程状态分析
)
public static void test(int param) throws InterruptedException {
System.out.println("==============="+Thread.currentThread().getName()+"操作之前的a值:"+a+"===================");
// 先让 线程进行操作之前 都能 先拿值(造成线程安全问题)
Thread.sleep(1000);
a += param;
System.out.println("==============="+Thread.currentThread().getName()+"进行加"+param+"操作之后的a值:"+a+"=============");
}
thread1执行test(1)之后 现在 thread2方法栈中 a的值 也已经改变,
private static void run() {
try {
test(1);
// 代码执行到此处时 a 的值 已经变成了 1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
note: 文章用于学习交流,如有错误之处,请大家指正