JUC- volatile
理论,代码,总结。
1,线程可见性
2 线程可见性代码验证:
2.1 未添加 volatile 关键字之前
package com.test.thread.volatile_;
import java.util.concurrent.TimeUnit;
public class VolatileDemo {
public static void main(String[] args) {
MyData myData = new MyData();
new Thread(() -> {
System.out.println("子线程执行开始。。。");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
myData.update();
System.out.println("子线程执行结束。。。number:" + myData.number);
}, "aaa").start();
// 第二个线程
while (myData.number == 0){
// main线程一直在这里等待,直到number被修改为止
}
System.out.println("main 方法执行结束。。number: " + myData.number);
}
}
class MyData{
int number = 0;
public void update(){
number = 60;
}
}
控制台打印结果:
子线程执行开始。。。
子线程执行结束。。。number:60
2.2 添加 volatile 关键字之后,保证了线程之间的可见性
package com.test.thread.volatile_;
import java.util.concurrent.TimeUnit;
/**
* Created by husz1 on 2019/12/17.
*/
public class VolatileDemo {
public static void main(String[] args) {
MyData myData = new MyData();
new Thread(() -> {
System.out.println("子线程执行开始。。。");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
myData.update();
System.out.println("子线程执行结束。。。number:" + myData.number);
}, "aaa").start();
// 第二个线程
while (myData.number == 0){
// main线程一直在这里等待,直到number被修改为止
}
System.out.println("main 方法执行结束。。number: " + myData.number);
}
}
class MyData{
volatile int number = 0;
public void update(){
number = 60;
}
}
控制台输出结果为:
子线程执行开始。。。
子线程执行结束。。。number:60
main 方法执行结束。。number: 60
3 volatile 不保证原子性
底层字节码文件
写值时有可能写覆盖:
3.1 怎样保证原子性
1,验证volatile的可见性
- 1.1 假如 int number = 0; number 变量之前根本没有添加 volatile 关键字修饰,没有可见性
- 1.2 添加 volatile,可以解决可见性问题
2,验证volatile 不保证原子性
- 2.1 原子性指的是什么意思?
不可分割,完整性,也即某个线程正在做某个具体业务时,中间不可以被加塞或者被分割,需要整体完整
要么同时成功,要么同时失败 - 2.2 volatile 不保证原子性的案例演示
- 2.3 为什么?
- 2.4 如何解决原子性?
加sync
直接使用juc下AtomicInteger
package com.test.thread.volatile_;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by husz1 on 2019/12/17.
*/
class MyData{
volatile int number = 0;
public void update(){
number = 60;
}
// 请注意,此时number前面是加了volatile关键字修饰的,volatile不保证原子性
public void addPlusPlus(){
number++;
}
AtomicInteger atomicInteger = new AtomicInteger();
public void addMyAtomic(){
atomicInteger.getAndIncrement();
}
}
/**
* 1,验证volatile的可见性
* 1.1 假如 int number = 0; number 变量之前根本没有添加 volatile 关键字修饰,没有可见性
* 1.2 添加 volatile,可以解决可见性问题
*
* 2,验证volatile 不保证原子性
* 2.1 原子性指的是什么意思?
* 不可分割,完整性,也即某个线程正在做某个具体业务时,中间不可以被加塞或者被分割,需要整体完整
* 要么同时成功,要么同时失败
* 2.2 volatile 不保证原子性的案例演示
* 2.3 为什么?
* 2.4 如何解决原子性?
* * 加sync
* * 直接使用juc下AtomicInteger
*/
public class VolatileDemo {
public static void main(String[] args) {
// seeOkByVolatile();
MyData myData = new MyData();
for (int i = 0; i < 20; i++) {
new Thread(() -> {
for (int i1 = 0; i1 < 1000; i1++) {
myData.addPlusPlus();
myData.addMyAtomic();
}
}, String.valueOf(i)).start();
}
while (Thread.activeCount() > 2){
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + "主线程。。。。number:" + myData.number);
System.out.println(Thread.currentThread().getName() + "主线程。。。。atomicInteger:" + myData.atomicInteger);
}
// volatile保证线程可见性
private static void seeOkByVolatile() {
MyData myData = new MyData();
new Thread(() -> {
System.out.println("子线程执行开始。。。");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
myData.update();
System.out.println("子线程执行结束。。。number:" + myData.number);
}, "aaa").start();
// 第二个线程
while (myData.number == 0){
// main线程一直在这里等待,直到number被修改为止
}
System.out.println("main 方法执行结束。。number: " + myData.number);
}
}