关于单身的多线程的东西

时间:2014-12-09 11:15:35

标签: java multithreading

我使用单例来读取配置:

Class Property {
      private String username;
      private String password;
      private static Property props;

      public String getUsername() {
          return username;
      }
      public String getPassword() {
          return password;
      }

      public static Property getInstance() {
          if(props == null) {
          synchronized(Property.class) {                
                   props = new Property();
                   props.initial();
              } 
          }
          return props;
      }

      public void initial() {
          Properties prop = new Properties();
          prop.load(new FileInputStream(new File("application.properties")));
          username = prop.getProperty("username");
          password = prop.getProperty("password");
      }
}

然后,在第一个帖子中,我得到了一个Property实例,例如props = Property.getInstance

我调用了方法getUsername()getPassword(),如下所示:

props.getUsername() / props.getPassword()

但是,这两种方法返回null 。在第二个线程和后面的线程中,我可以从这两个方法中获取用户名和密码。

我不知道为什么会这样。有人可以帮我这个吗?

4 个答案:

答案 0 :(得分:4)

props方法

处将静态prop更改为initial()
public void initial() {
    Properties prop = new Properties();
    prop.load(new FileInputStream(new File("application.properties")));
    username = prop.getProperty("username");
    password = prop.getProperty("password");
}

答案 1 :(得分:1)

"道具"执行新Property()后不再为null。因此,即使props - 方法未完全执行,也可能会返回initial()

请尝试以下代码:

public static Property getInstance() {
      synchronized(Property.class) {                
      if(props == null) {
               props = new Property();
               props.initial();
          } 
      }
      return props;
  }

答案 2 :(得分:0)

我认为上面代码中的props.getProperty在发布问题时是一个错字。

在synchronized语句之前,检查props == null。可能已创建道具(新属性),因此不为空,但对初始的调用尚未完成。因此,在调用getUsername / password之前,getInstance返回的对象尚未正确初始化。最简单的解决方案是使整个方法同步,但这可能是性能问题。

此外,使用当前实现,您最终可能会创建单例的两个实例。例如。如果props == null并且最终两个线程都进入synchronized块。你应该检查同步部分中的props是否为null,以避免创建两个实例(参见:http://en.wikipedia.org/wiki/Double-checked_locking

处理多线程单例的更优雅方式可能是按需初始化习语(http://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom)。

答案 3 :(得分:0)

antonis_wrx和Andy N.所说的是你的同步不是"宽"够:

1: if(props == null) {
2:     synchronized(Property.class) {                
3:         props = new Property();
4:         props.initial();
5:     } 
6: }

考虑并行执行2个线程。线程A执行第1行,props == null返回true。在此之后,OS切换到线程B.线程B也执行相同的第1行,并且检查仍然返回true(props仍然为null)。现在两个线程将继续并执行synchronized块。

所以说线程A首先在Property.class上获取监视器(第2行)并初始化道具(第2-5行)。现在线程B可以自由地获取第2行中的监视器 - 它执行第3行,此时,线程C调用getInstance().getUsername()

线程C getInstance执行返回false的第1行,然后返回props(它刚刚由线程B构建到new Property())。在这个未初始化的Property对象上调用getUsername()会给出您看到的null。

请注意,对于此示例,Thread C可能也是相同的Thread A(我只是想让它更容易阅读)。

您可以使用已建议的内容解决问题(同步整个getInstance方法)。另一种方法是使用静态块为您执行初始化,如下所示:

Class Property {
    private String username;
    private String password;
    private static Property props;

    static {
        props = new Property();
        props.initial();
    }

    ...
}