Java多线程中volatile的场景应用

版权声明:本文为博主原创文章,转载请注明出处 浅然的专栏 https://blog.csdn.net/w_linux/article/details/82832544

一、场景简述

笔者在看多线程通信相关问题时,不使用等待/通知机制实现多线程通信的时候,发现b线程没有与a线程发生正常通信。


二、场景实现

如下是未发生正常通信的代码

1、MyList类

package waitnotify;

import java.util.ArrayList;
import java.util.List;

/**
 * @author: linjie
 * @description: 不使用等待/通知机制实现线程间的通信 list类
 * @create: 2018/09/24 18:46
 */
public class MyList {
    private List list = new ArrayList();
    //向list中添加数据
    public void add(){
        list.add("xlj");
    }
    //返回list的大小
    public int size(){
        return list.size();
    }
}

2、线程类A

package waitnotify;

/**
 * @author: linjie
 * @description: 不使用等待/通知机制的线程类A
 * @create: 2018/09/24 18:50
 */
public class ThreadA extends Thread{
    private MyList list;
    //构造器
    public ThreadA(MyList list){
        super();
        System.out.println("a....");
        this.list = list;
    }
    @Override
    public void run(){
        try {
            for (int i = 0;i < 10;i++){
                list.add();
                System.out.println("添加了"+(i+1)+"个元素");
                Thread.sleep(1000);
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }
}

3、线程类B

package waitnotify;

/**
 * @author: linjie
 * @description: 不使用等待/通知机制的线程类B
 * @create: 2018/09/24 19:12
 */
public class ThreadB extends Thread{
    private MyList list;
    public ThreadB(MyList list){
        super();
        System.out.println("b....");
        this.list = list;
    }
    @Override
    public void run(){
        try{
            while (true){
                if (list.size() == 5){
                    System.out.println("==5了,线程b要退出了!");
                    throw new InterruptedException();
                }
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

4、main类

package waitnotify;

/**
 * @author: linjie
 * @description:不使用等待/通知机制的main类
 * @create: 2018/09/24 19:20
 */
public class Test {
    public static void main(String[] args){
        MyList service = new MyList();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
    }
}

运行结果如下

可以看到程序处于死循环,并且没有出现 “==5了,线程b要退出了!”


三、场景分析

该现象与Java内存模型有关,Java内存模型如图,可以看出每个线程都有一个自己的本地内存空间,线程执行时,先把变量从主内存读取到线程自己的本地内存空间,然后再对该变量进行操作。然后对该变量操作完后,在某个时间再把该变量刷新回主内存

所以场景代码中,A线程将list读取到本地内存,修改后,再刷新回主内存。

而在JVM 设置成 -server模式运行程序时,线程会一直在私有堆栈中读取list大小,所以B线程一直无法读取到A线程改变的list变量,从而处于死循环,并无法出现 “==5了,线程b要退出了!”

(图片摘取地址在文末)


四、解决方案

在线程类B中对其变量前加volatile,作用即:它强制线程从主内存中取 volatile修饰的变量

volatile private MyList list;

加上之后运行结果正常


参考

http://www.cnblogs.com/hapjin/p/5492880.html

猜你喜欢

转载自blog.csdn.net/w_linux/article/details/82832544