这是我的代码。
public class PropertyLoader {
private Properties appProperties;
/**
* The instance.
*/
private static PropertyLoader inst = null;
/**
* Instantiates a new property data loader.
*/
private PropertyLoader() {
try
{
appProperties = new Properties();
appProperties.load(this.getClass().getClassLoader().getResourceAsStream("app.properties"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static PropertyLoader getInstance() {
if (inst == null) {
inst = new PropertyLoader();
}
return inst;
}
}
public String getPropertyAPP(String key) {
return appProperties.getProperty(key);
}
}
getPropertyAPP
方法需要同步:它是一个单例,因此许多线程可以同时访问同一个实例并调用它。
有人能以正确的方式向我推荐吗?
答案 0 :(得分:3)
您可以使用以下解决方案
public class PropertyLoader {
private Properties appProperties;
/** The instance. */
private static PropertyLoader inst = null;
static{
inst = new PropertyLoader();
}
/**
* Instantiates a new property data loader.
*/
private PropertyLoader() {
try
{
appProperties = new Properties();
appProperties.load(this.getClass().getClassLoader().getResourceAsStream("app.properties"));
}
catch(IOException e)
{
e.printStackTrace();
}
}
public static PropertyLoader getInstance() {
return inst;
}
public String getPropertyAPP(String key) {
return appProperties.getProperty(key);
}
}
答案 1 :(得分:1)
一个更简单的解决方案,也是线程安全的,是使用静态初始化来初始化静态字段。
public class AppProperties {
private static final Properties appProperties;
static {
try {
appProperties = new Properties();
appProperties.load(AppProperties.class
.getClassLoader().getResourceAsStream("app.properties"));
} catch(IOException e) {
e.printStackTrace();
}
}
public String get(String key) {
return appProperties.getProperty(key);
}
public String get(String key, String defaultValue) {
return appProperties.getProperty(key, defaultValue);
}
}
答案 2 :(得分:0)
您的getInstance()
方法中发生了大规模的竞争状况。如果多个线程同时调用getInstance()
,您将创建多个实例并将它们依次分配给静态变量。考虑到你在这里所做的事情,这不会导致任何逻辑问题,但这意味着你做的工作超出了必要的范围。
我建议你做一些关于Singleton模式的阅读,为什么它不好,以及如何在Java中以安全的方式实现它。
但简而言之,不要使用Singleton模式,它会被严重破坏,并且会使使用此对象的任何代码紧密耦合,并且会阻碍您进行任何类型的隔离测试。
答案 3 :(得分:0)
您的代码有几个问题:
(a)您确定需要延迟初始化吗?初始化的成本必须是显着的,并且从不使用资源的机会必须是非零的。另外:最好在程序启动期间失败,而不是在首次访问资源时的某个不确定时刻失败。这实际上取决于您的应用程序。
(b)实现延迟初始化的一种方法是使用正确版本的双重检查锁定(volatile关键字是必不可少的):
private static volatile PropertyLoader inst;
...
public static PropertyLoader getInstance() {
if (inst == null) {
synchronized(PropertyLoader.class) {
if (inst == null) {
inst = new PropertyLoader();
}
}
}
return inst;
}
这篇维基百科文章解释了为什么这样有效(从Java 5开始,但之前没有):http://en.wikipedia.org/wiki/Double-checked_locking
(c)在大多数情况下捕获异常并简单地记录它们是完全错误的。在您的情况下,getPropertyAPP不会返回任何属性。如果明确声明属性的存在是可选的,则可能没问题。