volatile关键字的相关学习记录


1:volatile是什么?

Volatile是java虚拟机提供的一种轻量级的同步机制,具有 三大特性,分别是:保证可见性、不保证原子性、禁止指令重排

可见性:

概念:每一个线程都有自己的工作内存,线程不能直接操作主内存的值,必须把主内存的数据拷贝回工作内存进行更改后,刷新回主内存,并及时通知其他线程

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可以禁止重排序,主要是在多线程环境下,变量的顺序可能发生变化 从而导致结果不可预测的问题。

代码:单例模式使用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();
        }

    }



}