volatile 关键字

1.引入volatile的作用

先跑一下这个程序:

RunThread.java:

package com.examp.jasonpeng;

public class RunThread extends Thread {
//    volatile private boolean isRunning = true;
    private boolean isRunning = true;
    public boolean isRunning(){
        return isRunning;
    }
    public void setRunning(boolean isRunning){
        this.isRunning = isRunning;
    }

    @Override
    public void run() {
//        super.run();
        System.out.println("进入run了");
        while(isRunning == true){

        }
        System.out.println("线程被停止了!");
    }

}

 

public class Practise {
//    static  final MyThread t = new MyThread();
//    static Thread t1 = null, t2 =null;

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InterruptedException {
        try{
            RunThread thread = new RunThread();
            thread.start();
            Thread.sleep(1000);
            thread.setRunning(false);
            System.out.println("已经赋值为false");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

 

 

 

 是什么原因出现了死循环呢?

原因是在启动RunThread.java 线程时,变量private boolean isRunning = true;存在于公共堆栈及线程的私有堆中。

线程一直在私有堆栈中取得isRunning的值是true。而代码thread.setRunning(false);虽然被执行,更新的却是公共堆栈中的isRunning 变量值false,所以一直就是死循环的状态.

内存结构如图:

 

 这个问题其实就是私有堆栈中的值和公共堆栈中的值不同步造成的。解决这样的问题就要使用volatile关键字了,它的主要作用就是当线程访问isRunning这个变量时,强制性从公共堆栈中进行取值。

现将RunThread.java代码更改如下:

package com.examp.jasonpeng;

public class RunThread extends Thread {
    volatile private boolean isRunning = true;
//    private boolean isRunning = true;
    public boolean isRunning(){
        return isRunning;
    }
    public void setRunning(boolean isRunning){
        this.isRunning = isRunning;
    }

    @Override
    public void run() {
//        super.run();
        System.out.println("进入run了");
        while(isRunning == true){

        }
        System.out.println("线程被停止了!");
    }

}

程序运行结果:

 

 

通过使用volatile关键字,强制的从公共内存中读取变量的值。

内存结构如图:

 

 

 

 

关键字volatile虽然增加了实例变量在多个线程之间的可见性,但它却不具备同步性,那么也就不具备原子性。

下面来进行测试:

MyThread.java:

 

public class MyThread extends Thread{
    volatile public static int count;
    private static void addCount(){
        for(int i = 0;i<100;++i){
            count++;
        }
        System.out.println("count=" + count);
    }

    @Override
    public void run() {
        addCount();
    }
}

 

public class Practise {
//    static  final MyThread t = new MyThread();
//    static Thread t1 = null, t2 =null;

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InterruptedException {
       MyThread[] mythreadArray = new MyThread[100];
       for(int i =0;i<100;++i){
           mythreadArray[i] = new MyThread();
       }
       for(int i = 0;i<100;++i){
           mythreadArray[i].start();
       }
    }
}

运行结果如下:

 修改后的代码:

public class MyThread extends Thread{
    volatile public static int count;
   synchronized private static void addCount(){ // 修改
        for(int i = 0;i<100;++i){
            count++;
        }
        System.out.println("count=" + count);
    }

    @Override
    public void run() {
        addCount();
    }
}

 

 

 

 

 

 

 

 

posted @ 2021-02-27 02:21  JasonPeng1  阅读(45)  评论(0编辑  收藏  举报