0

我有一个在不同线程中使用的数据库对象:

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()绕过同步。

4

3 回答 3

5

一般来说,您不应该使用互斥锁来保护对最终引用的访问。因为这类字段根据Java Memory Model具有安全发布。

在您的部分情况下, PoolDataSourceImpl(或PoolXADataSourceImpl)能够更改自己的状态抛出方法getConnection()connection.close();. 所以你应该检查你的 PoolDataSource 实现是否是线程安全的。因此 ,Oracle® Database JDBC Developer's Guide and Reference看起来 DataSource 是线程安全的,但不是连接。

Oracle JDBC 驱动程序为使用 Java 多线程的应用程序提供全面支持并对其进行了高度优化。对连接的受控串行访问,例如连接缓存提供的访问,既是必要的,也是鼓励的。但是,Oracle 强烈反对在多个线程之间共享数据库连接。避免允许多个线程同时访问一个连接。如果多个线程必须共享一个连接,请使用规范的开始使用/结束使用协议。

于 2013-09-20T10:09:16.190 回答
3

final仅当字段不可变时才不需要同步;final String例如,无需同步s。当您有一个像这样的字段不包含不可变对象时,您仍然需要同步,除非对象本身(如您的PoolDataSource)是线程安全的。

于 2013-09-20T10:08:34.477 回答
1

这可能没有必要。必须使用时有几个原因synchronized

  1. 一个变量被线程 A 改变并被线程 B 读取。

    这不会发生在final变量上,所以这个原因就出来了。

  2. 您必须对几个变量进行更改,而其他线程必须要么一个都看不到,要么全部看不到。

    不需要访问单个字段synchronized

  3. 您必须保护复杂对象的内部状态。Map.put()是这样的情况。虽然x.put()只是一次访问,但地图内部状态的更新会改变几个变量,所以你需要synchronized这个。

    问题是:你需要它吗pool.getConnection()connection.close()

    可以在您使用的库/框架的文档中找到答案。

一般来说,创建连接池是为了为多线程应用程序保留一个连接池,因此它们应该可以安全地调用,而无需您锁定。

于 2013-09-20T10:35:51.683 回答