我希望JdbcPersistenceManager始终只有一个jdbcConnection,并通过以下方式实例化:JdbcConnectionManager.getJdbcConnection()
这是一个简单的模式,取自(2004-11-01 | Head First Design Patterns | O'Reilly Media | 688p | by Elisabeth Freeman | ISBN-0596007124),可能被滥用,误解和不合适。
synchronized()是否应锁定“this”或专门用于跟踪锁定的特定新(静态?)字段?我该怎么做?
public class JdbcPersistenceManager implements PersistenceManager {
private volatile Connection jdbcConnection;
/* ... */
private Connection getJdbcConnection() throws JdbcConnectionFailureException {
if (jdbcConnection == null) {
synchronized (this) {
if (jdbcConnection == null) {
jdbcConnection =
JdbcConnectionManager.getJdbcConnection(jdbcConnectionParameters);
}
}
}
// label:here
return jdbcConnection;
}
}
假设jdbcConnection的实例化,即使在标记为“label:here”的点上,如果我们想要,只是为了参数的缘故,如何最好地检查连接是否仍然有效并重新创建它,如果它不是? / p>
ConnectionPooling不是我想在这里做的。只有一个连接......如果它是“空”或“无效”,则重新生成/重新打开它。
编辑:
我想让jdbcConnection做的是:
1)输出jdbcConnections,确保在任何给定时间只存在其中一个(不允许客户端保留对2个不同连接的引用)
和
2)如果由于某种原因它被关闭,则重新生成(即重新调用JdbcConnectionManager.getJdbcConnection())“private volatile Connection jdbcConnection”字段
(例如,客户端1出现,获取连接,但关闭它,客户端2出现,连接不为空但不能使用,所以她得到一个再生的。)
注意:我意识到没有什么能阻止客户端1获得连接,而客户端2获得相同的连接,如设计,并在客户端1通过他的引用关闭它后仅使用它一毫秒......我不知道如果那是可以解决的?
答案 0 :(得分:0)
是的,synchronized()锁仅用于跟踪锁,因此当他们看到 jdbcConnection = NULL 时,没有两个线程实例化 jdbcConnection 。
如果要检查// label:here
位置的连接的完整性。
您可以递归调用getJdbcConnection()方法。
return jdbcConnection!=NULL?jdbcConnection:jdbcConnection();
答案 1 :(得分:0)
双重检查锁定应该在不在this
上的类上完成:
if (jdbcConnection == null) {
synchronized (JdbcPersistenceManager.class) {
if (jdbcConnection == null) {
jdbcConnection =
JdbcConnectionManager.getJdbcConnection(jdbcConnectionParameters);
}
}
}
根据连接检查,您可以按照建议在创建后执行此操作。我不会递归地调用该方法,仅null
Connection
实例,并尝试再次调用getJdbcConnection()
。
答案 2 :(得分:0)
如果要实现Singleton模式,那么您需要确保给定类的单个实例,这就是Singleton模式通常使用静态实例实现的原因。
避免任何同步问题的最佳方法是初始化单行内联或静态初始化器,因为初始化发生在首次访问类时,并且保证初始化不会被并发性破坏,即在完全初始化之前,不能使用该类:
public class Singleton {
private static final Singlenton instance = new Singleton();
//private constructor here
public static Singleton getIntance() { return instance; }
}
现在,如果你想懒洋洋地初始化你的单例,那么你将被迫考虑多个线程可能同时尝试获取它的实例的可能性,在这种情况下,你将同步对你的类的访问:
public class Singleton {
private static Singlenton instance;
//private constructor here
public static synchronized Singleton getIntance() {
if(instance == null) {
intance = new Singleton();
}
return instance;
}
}
有些人会建议减少同步代码的范围,这样也减少了给定线程锁定的时间。在这种情况下,您可以执行以下操作:
public class Singleton {
private static Singlenton instance;
//private constructor here
public static Singleton getIntance() {
synchronized(Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
return instance;
}
}
在最后一个示例中,一旦安全地分配了单例实例,您就可以同时返回它。
另一种懒惰初始化Singleton的模式包括使用静态内部类:
public class Singleton {
//private constructor
private static class SingletonHolder {
public static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
这意味着在首次访问内部类之前不会创建单例,直到调用getIntance方法才会发生。再一次,由于类初始化以线程安全的方式发生,因此可以确保单例的创建不会受到损害。
答案 3 :(得分:0)
除了@ edalorzo的综合列表之外,还有一种技术,使用singleton
提供的enum
机制。有一个很好的例子here,它可能看起来有点像这样。
public enum SingletonConnection {
INSTANCE;
// Not sure if this needs to be volatile.
private volatile Connection jdbcConnection;
private SingletonConnection() {
jdbcConnection = JdbcConnectionManager.getJdbcConnection(jdbcConnectionParameters);
}
public Connection getConnection() {
return jdbcConnection;
}
}
// use it as ...
SingletonConnection.INSTANCE.getConnection ();
但是,您可能对使用ThreadLocal
连接的想法感兴趣。