volatile关键字的相关学习记录
概念:每一个线程都有自己的工作内存,线程不能直接操作主内存的值,必须把主内存的数据拷贝回工作内存进行更改后,刷新回主内存,并及时通知其他线程
import java.util.concurrent.TimeUnit; public class test { public static void main(String[] args) { MyData myData = new MyData(); new Thread(() -> { try { TimeUnit.SECONDS.sleep(3); }catch (Exception e){ } myData.addTo60(); System.out.println(Thread.currentThread().getName() + " update value to 60 :" + myData.number); },"AAA").start(); while (myData.number == 0){ } System.out.println(Thread.currentThread().getName() + " get value mydata.number :" + myData.number); } } class MyData{ /** * 当加了volatile这个关键字的时候,由于其中一个线程修改完毕 立即通知,那么另一个线程就会收到值被修改,则在上述循环方法中将会跳出 并结束 * * 如果不加,则其中一个线程将不会收到值被修改的情况,导致while循环将一直存在 */ volatile int number=0; public void addTo60(){ this.number=60; } }
不保证原子性:
代码:
import java.util.concurrent.TimeUnit; public class test { public static void main(String[] args) { //验证volatile不保证原子性的问题 MyData myData = new MyData(); for (int i = 1; i <= 20; i++) { new Thread(()->{ for (int j = 1; j <= 1000; j++) { myData.addPlusPlus(); } },String.valueOf(i)).start(); } //等待执行完成, while (Thread.activeCount()> 2){ Thread.yield(); } System.out.println(Thread.currentThread().getName() + " number:" + myData.number); } } class MyData{ volatile int number=0; public void addPlusPlus(){ this.number++; } } 打印结果将不可预测
处理非原子性问题
import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class test { public static void main(String[] args) { //验证volate不保证原子性的问题 MyData myData = new MyData(); for (int i = 1; i <= 20; i++) { new Thread(()->{ for (int j = 1; j <= 1000; j++) { myData.addPlusPlus(); myData.addAtomic(); } },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() + " atomic:" + myData.atomicInteger); } } class MyData{ int number=0; public void addPlusPlus(){ number++; } AtomicInteger atomicInteger = new AtomicInteger(); public void addAtomic(){ atomicInteger.getAndIncrement(); } }
禁止指令重排:
编译器和操作系统会对指令进行优化和重排序,通过volatile可以禁止重排序,主要是在多线程环境下,变量的顺序可能发生变化 从而导致结果不可预测的问题。
import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class test { //双端检索 + volatile 禁止指令重排序 private static volatile test t = null; private test(){ System.out.println(Thread.currentThread().getName() + " test-构造方法!"); } private static test getTestInstince(){ if(t == null){ synchronized (test.class){ if(t == null){ t = new test(); } } } return t; } public static void main(String[] args) { for (int i = 0; i < 10; i++) { new Thread(() -> { System.out.println(test.getTestInstince()); },Thread.currentThread().getName() + String.valueOf(i)).start(); } } }