为什么这段代码和书上的执行结果不一致?

代码如下:

package com.obj;

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

public class MyList {
    private   List list = new ArrayList();
    public  void  add(){
        list.add("高红艳");
    }

    public  int size(){
        return list.size();
    }
}
package com.thread;

import com.obj.MyList;

public class ThreadA extends Thread {
    private MyList list;
    public ThreadA(MyList list){
        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();
        }
    }
}
package com.thread;

import com.obj.MyList;

public class ThreadB extends  Thread {
    private MyList list;
    public ThreadB(MyList list){
        this.list=list;

    }

    @Override
    public void run() {
        super.run();
        try {
                while (true){

                    if (list.size() == 5) {
                    System.out.println("==5,线程b要退出了");
                    throw new InterruptedException();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package com.demo;

import com.obj.MyList;
import com.thread.ThreadA;
import com.thread.ThreadB;


public class Run1 {
    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();
    }
}

clipboard.png
我的第一个解决方法是考虑list对象是不是没有及时刷新到主存,所以我就在MyList.java中给list添加volatile修饰符

clipboard.png
改了之后执行结果

clipboard.png
这也与书上的执行结果一致,但是我觉得应该不是这个原因,于是我去掉volatile,并在B线程if语句之前打印list.size()

clipboard.png
执行结果如下

clipboard.png
所以现在不太清楚这个是什么原因造成的

阅读 2k
3 个回答

cpu 运行的很快,多线程运行的情况太多了,有可能是a线程先抢占了cpu也有可能是b线程先抢占了cpu,他们之前的运行情况存在了很多的不确定性,而volatile ,确实有这个功能,就是list的状态能够实时的被多个线程实时共享.

这是书上的代码执行结果

图片描述

这实际涉及到了内存屏障的原理,

System.out.println(list.size());

这一行的中,其实是隐含了一个synchronized关键词的,这个关键词实际上是保证了在读数据之前可以拿到最新数据,所以你可以试一下把这个

System.out.println(list.size());

改成

synchronized (this) {
}

可以获得相同的结果。
这也是符合jvm内存设计的预期的。
至于volatile也可以获得相同的结果,也是内存屏障在发挥效用。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题