我有一个在不同线程中使用的数据库对象:
import java.sql.Connection;
import oracle.ucp.jdbc.PoolDataSourceFactory;
import oracle.ucp.jdbc.PoolDataSource;
public class Database
{
private final PoolDataSource pool = PoolDataSourceFactory.getPoolDataSource();
protected Connection connect ()
{
synchronized (pool) { return pool.getConnection(); }
}
protected void disconnect (Connection connection)
{
synchronized (pool) { connection.close(); }
}
}
是否有必要同步对pool
成员的访问权限?或者是否足以避免显式同步?
如果需要同步,代码将被破坏,因为没有必要调用disconnect
来关闭连接。该类中的某些代码可以绕过同步调用connection.close()
。
答案 0 :(得分:5)
通常,您不应使用互斥锁来保护对最终引用的访问。因为这类字段根据Java Memory Model安全发布。
在部分情况下PoolDataSourceImpl(或PoolXADataSourceImpl)能够更改自己的状态抛出方法getConnection()
和connection.close();
。所以你应该检查一下你的PoolDataSource的实现是一个线程安全的。因此
Oracle® Database JDBC Developer's Guide and Reference看起来像DataSource是线程安全的,但不是Connection。
Oracle JDBC驱动程序提供全面支持,并且非常高 针对使用Java多线程的应用程序进行了优化。受控 对连接的串行访问,例如连接提供的连接 缓存,既是必要的,也是鼓励的。但是,Oracle强烈 不鼓励在多个线程之间共享数据库连接。 避免允许多个线程同时访问连接。 如果多个线程必须共享连接,请使用规范 开始使用/最终使用协议。
答案 1 :(得分:3)
仅当final
字段不可变时才需要同步;例如,无需同步final String
。如果你有一个不包含不可变对象的字段,你仍然需要同步,除非对象本身(如你的PoolDataSource
)是线程安全的。
答案 2 :(得分:1)
可能没有必要。必须使用synchronized
时有几个原因:
变量被更改为线程A并由线程B读取。
final
变量不会发生这种情况,所以这个原因就出来了。
您必须对多个变量进行更改,其他线程必须看不到或全部。
访问单个字段不需要synchronized
您必须保护复杂对象的内部状态。 Map.put()
就是这种情况。虽然x.put()
只是一次访问,但地图内部状态的更新会更改多个变量,因此在这种情况下您需要synchronized
。
问题是:您是否需要pool.getConnection()
或connection.close()
?
您可以在您使用的库/框架的文档中找到答案。
一般来说,创建连接池是为了保留多线程应用程序的连接池,因此无需锁定就可以安全地调用它们。