Java中的并发对象创建 [英] Concurrency object creation in Java

查看:249
本文介绍了Java中的并发对象创建的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在读Brian Goetz的一本书实践中的Java并发。第3.5和3.5.1段包含我无法理解的陈述。

I'm reading a book "Java concurrency in practice" by Brian Goetz. Paragraphs 3.5 and 3.5.1 contains statements that I can not understand.

考虑以下代码:

public class Holder {
  private int value;
    public Holder(int value) { 
    this.value = value;
  }

  public void assertValue() {
    if (value != value) throw new AssertionError("Magic");
  }
}

class HolderContainer {
  // Unsafe publication
  public Holder holder;

  public void init() {
    holder = new Holder(42);  
  }
}

作者声明:


  1. 在Java中,对象构造函数首先在子类构造函数运行之前将默认值写入所有字段。

  2. 因此,可以将字段默认值视为陈旧值。

  3. 线程第一次读取字段时可能会看到陈旧值,然后是下次更新的值,这就是assertN可以抛出AssertionError的原因。

所以,根据文字,一些不幸的时机可能值= 0;在下一刻,值= 42。

So, according to the text, with some unlucky timing it is possible that value = 0; and in the next moment value = 42.

我同意第1点,即Object构造函数首先使用默认值填充字段。但我不明白第2点和第2点3。

I agree with point 1 that Object constructor firstly fills fields with default values. But I don't understand points 2 & 3.

让我们更新作者代码并考虑以下示例:

Let's update authors code and consider the following example:

public class Holder {
  int value;

  public Holder(int value) {
    //Sleep to prevent constructor to finish too early
    try {
     Thread.sleep(3000);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    this.value = value;
  }

  public void assertValue()  {
    if(value != value) System.out.println("Magic");
  }
}

我添加了Thread.sleep(3000),强制线程在对象完全构造之前等待。

I've added Thread.sleep(3000), to force thread to wait before object will be fully constructed.

public class Tests {

  private HolderContainer hc = new HolderContainer();

  class Initialization implements Runnable {
    public void run() {
      hc.init();
    }
  }

  class Checking implements Runnable {
    public void run() {
      hc.holder.assertValue();
    }
  }

  public void run() {
    new Thread(new Initialization()).start();
    new Thread(new Checking()).start();
  }
}

例如:


  1. 第一个线程inits holder对象

  2. 第二个线程调用assertValue

主线程运行两个线程:


  1. new Thread(new Initialization())。start();完全构造Holder对象花了3秒钟

  2. 新线程(new Checking())。start();因为Holder对象仍然没有构造代码会抛出 NullPointerException

  1. new Thread(new Initialization()).start(); It tooks 3 seconds to fully construct Holder object
  2. new Thread(new Checking()).start(); since Holder object still not constructed code will throw an NullPointerException

因此,当字段不可能模拟情况有默认值。

Therefore, it's impossible to emulate situation when field has default value.

我的问题:


  1. 作者对此并发性有误问题?

  2. 或者无法模拟字段默认值的行为?


推荐答案

没有使用您的代码重现它。以下是模拟不安全发布的示例。策略是让一个线程发布 Holder 并让另一个检查它的值。

Did not reproduce it with your code. Here is an example to emulate un-safe publication. The strategy is let one thread publication Holder and let another check its value.

class Holder {
    private volatile int value;

    public Holder(int value, HolderContainer container) {
        container.holder = this;  // publication this object when it is not initilized properly
        try {
            Thread.sleep(10);  
        } catch (Exception e) {

        }
        this.value = value; // set value
    }

    public int getValue() {
        return value;
    }
}

class HolderContainer {

    public Holder holder;

    public Holder getHolder() { 
        if (holder == null) { 
            holder = new Holder(42, this);
        }
        return holder;
    }
}


public class Tests {

    public static void main(String[] args) {
        for (int loop = 0; loop < 1000; loop++) {
            HolderContainer holderContainer = new HolderContainer();
            new Thread(() -> holderContainer.getHolder()).start();
            new Thread(() -> {
                Holder holder = holderContainer.getHolder();
                int value1 = holder.getValue();  // might get default value
                try {
                    Thread.sleep(10);
                } catch (Exception e) {

                }
                int value2 = holder.getValue(); // might get custom value
                if (value1 != value2) {
                    System.out.println(value1 + "--->" + value2);
                }
            }).start();
        }
    }

}

这篇关于Java中的并发对象创建的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆