java ArrayList 的size值在多线程中可见性问题

ArrayList

hello! 想问下大家一个可见性的问题,如果使用ArrayList,开启两个线程,一个线程往这个集合中添加数据,另一个线程中取这个集合的size值,为什么线程中取到的值一直取不到最新的值?

public void testVisibility3() {
        List<Object> list = new ArrayList<>();
        System.out.println("current list size:" + list.size());
        new Thread(() -> {
            System.out.println("thread 1 add ....");
            for (int i = 0; i < 10; i++) {
                list.add("index" + i);
                System.out.println("thread 1 add success size:" + list.size());
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("thread 1 add success");
        }).start();

        new Thread(() -> {
            System.out.println("thread 2 start =======");
            while (list.size() < 5) {
                // 这里不能使用System.out.println方法来进行测试,因为该方法是线程安全的,有同步标识,这样会导致list数据重新从主内存中加载一份
                //                System.out.print("thread 2 read size:" + this.list.size() + "\n");
            }
            System.out.println();
            System.out.println("thread 2 end =======");
        }).start();
    }

如果用main方法启动调用上面的方法,第二个线程一直不能结束,取不到最新的size值;

但如果定义一个对象,对象中有int值

public class Person implements Serializable {


    /** 年齡 */
    private int    age;


    /**
     * 空构造函数
     */
    public Person() {
        //
    }



    public void incrAge() {
        this.age++;
    }

    /**
     * Getter method for property <tt>age</tt>.
     *
     * @return property value of age
     */
    public int getAge() {
        return this.age;
    }

    /**
     * Setter method for property <tt>age</tt>.
     *
     * @param age
     *            value to be assigned to property age
     */
    public void setAge(int age) {
        this.age = age;
    }


    }

但是,我如果使用上面的对象,我对象中有个int值,如果我开启两个线程,一个线程对这个对象的int值赋值,另一个线程从这个对象中取这个int值,int值没有加其它的修饰符,只有个private; 但是取值的这个线程值不然等很久,就能获取到另一个线程赋的值

public void testVisibility4() {

        Person person = new Person();

        new Thread(() -> {
            System.out.println("thread 1 start ======= age =" + person.getAge());
            while (person.getAge() != 12) {
            }
            System.out.println("thred 1 age =======" + person.getAge());
            System.out.println("thread 1 end =======");
        }).start();

        new Thread(() -> {
            System.out.println("thread 2 modify ....");

            for (int i = 0; i < 12; i++) {

                person.incrAge();
            }
            System.out.println("thread 2 modify success");
        }).start();

    }

上面方法运行的结果,一般都会是:

thread 1 start ======= age =0
thread 2 modify ....
thread 2 modify success
thred 1 age =======12
thread 1 end =======

请问下,这个ArrayList在多线程中这个size和一个对象的int值在多线程中它们到底是如何处理的?可见性为什么会不一样了?

1个回答

建议去了解一下 Java 的内存模型,那个知识点会详细解释内存可见性问题。

generally2008
generally2008 但如果你通过TimeUnit.NANOSECONDS.sleep 加入这行代码,通过这种方式(虽然底层也是Thread.sleep),你里面的值设置的越小,这个方法中线程1运行成功率越高,值越大,成功率越低;在windows系统中是这样的。
4 个月之前 回复
generally2008
generally2008 但你不加这行代码,你用main运行试试,看testVisibility4这个方法,运行时间多多久?线程1完成
4 个月之前 回复
generally2008
generally2008 就拿我上面的案例;testVisibility4这个方法,你用main方法运行。如果你在该方法中加入了Thread.sleep,你会发现,它会无限放大你的工作内存同步不到主内存中线程2修改的值
4 个月之前 回复
generally2008
generally2008 那你可以写一个更简单的例子,就是你所了解的那种测试可见性的经典案例。如果你把Thread.sleep()去掉,你看看效果。
4 个月之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问