目录
目的
方便后续自己复习方便, 也是一次学习的记录.
资源
如何理解线程安全
线程安全要考虑的3个方面
可见性
一个线程对共享变量修改, 另一个线程可以看到最新的结果
有序性
一个线程内代码按照编写顺序执行, 没有指令重排的影响
原子性
一个线程内多行代码以一个整体运行, 期间不能有其他线程的代码插队. 没有线程切换的影响.
示例代码验证
volatile 不能保证原子性
/**
* volatile原子性例子: 不能保证原子性
* <p>
* 调试需要拆解"balance -= 5;" 使用Debug模式复现
*
* @author xiaozhengN [email protected]
* @since 2022-11-19 18:09:41
**/
@Slf4j
public class AddAndSubtract {
static volatile int balance = 10;
private static void subtract() {
balance -= 5;
}
private static void add() {
balance += 5;
}
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(2);
new Thread(() -> {
subtract();
latch.countDown();
}).start();
new Thread(() -> {
add();
latch.countDown();
}).start();
latch.await();
log.info("共享变量balance: {}", balance);
}
}
volatile 可保证可见性
/**
* volatile 可见性例子
*
* -Xint
*
* @author xiaozhengN [email protected]
* @since 2022-11-19 17:36:20
**/
@Slf4j
public class ForeverLoop {
// 共享变量, 控制 foo() 循环次数
static volatile boolean isStop = false;
public static void main(String[] args) {
new Thread(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
log.error("", e);
}
isStop = true;
log.info("修改共享变量成功: isStop: {}", isStop);
}).start();
new Thread(() -> {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
log.error("", e);
}
log.info("从主内存中获取共享变量, isStop: {}", isStop);
}).start();
foo();
}
static void foo() {
int i = 0;
while (!isStop) {
i++;
}
log.info("foo方法已结束, 循环次数为: {}", i);
}
}
volatile设置内存屏障保证有序性(难理解)
/**
* volatile 有序性例子
* <p>
* 没有测试成功, 报错: Unrecognized VM option 'StressCCP'
* java -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation -jar jcstress.jar -t main.daily.Reordering.Case1
* D:\17-JDKS\jdk-16.0.1\bin\java -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation -jar jcstress.jar -t main.daily.Reordering.Case1
*
* @author xiaozhengN [email protected]
* @since 2022-11-19 18:27:03
**/
public class Reordering {
@JCStressTest
@Outcome(id = {
"0, 0", "1, 1", "0, 1"}, expect = Expect.ACCEPTABLE, desc = "可接受的值")
@Outcome(id = "1, 0", expect = Expect.ACCEPTABLE_INTERESTING, desc = "感兴趣的值(发生指令重排)")
@State
public static class Case1 {
int x;
int y;
@Actor
public void actor1() {
x = 1;
y = 1;
}
@Actor
public void actor2(II_Result result) {
result.r1 = y;
result.r2 = x;
}
}
@JCStressTest
@Outcome(id = {
"0, 0", "1, 1", "0, 1"}, expect = Expect.ACCEPTABLE, desc = "可接受的值")
@Outcome(id = "1, 0", expect = Expect.FORBIDDEN, desc = "被禁止的值")
@State
public static class Case2 {
int x;
volatile int y;
@Actor
public void actor1() {
x = 1;
y = 1;
}
@Actor
public void actor2(II_Result result) {
result.r1 = y;
result.r2 = x;
}
}
@JCStressTest
@Outcome(id = {
"0, 0", "1, 1", "0, 1"}, expect = Expect.ACCEPTABLE, desc = "可接受的值")
@Outcome(id = "1, 0", expect = Expect.ACCEPTABLE_INTERESTING, desc = "感兴趣的值(发生指令重排)")
@State
public static class Case3 {
volatile int x;
int y;
@Actor
public void actor1() {
x = 1;
y = 1;
}
@Actor
public void actor2(II_Result result) {
result.r1 = y;
result.r2 = x;
}
}
}