在这种情况下,ServiceLocator执行查找操作的次数

时间:2014-10-17 14:28:20

标签: java

请您帮助我理解我们项目中的ServiceLocator类

这是我们的ServiceLocator班级

public class ServiceLocator
{
    private static ServiceLocator   instance;

    private Context                 initalContext;
    private Map                     cache;

    // return the singelton service locator
    public static ServiceLocator getInstance ()
            throws ServiceLocatorException
    {
        if (instance == null)
            instance = new ServiceLocator();
        return instance;
    }

    private ServiceLocator ()
    {
        try
        {
            this.initalContext = new InitialContext();
            this.cache = Collections.synchronizedMap(new HashMap());
        }
        catch (NamingException ex)
        {
            System.err.printf("Error in CTX lookup");
        }
    }

    public DataSource getDataSource (String dataSourceName)
    {
        DataSource datasource = null;
        try
        {
            if (this.cache.containsKey(dataSourceName))
                datasource = (DataSource)this.cache.get(dataSourceName);
            else
            {
                Context envContext = (Context)initalContext
                        .lookup("java:comp/env");
                datasource = (DataSource)envContext
                        .lookup(dataSourceName);
                this.cache.put(dataSourceName, datasource);
            }
        }
        catch (NamingException ex)
        {
            System.err.printf("Error in CTX lookup");
        }
        return datasource;
    }
}

关于上述代码我几乎没有问题。

  1. 是否有必要将其设为单例或静态同步方法??

  2. 为什么将dataSourceName放在地图缓存下? (如果有10个并发用户会进行10次或1次查找操作会发生什么情况)

  3. 是否只有一个用户可以同时使用数据库吗?

  4. 供您参考,这是使用此服务定位器的客户端

    private static final Logger logger = Logger.getLogger(MyObject.class);
    
    private Connection con;
    private DataSource dataSource;
    
    public MyObject()
    {
        this.dataSource = ServiceLocator.getInstance().getDataSource("jdbc/mydatabase");
    }
    

2 个答案:

答案 0 :(得分:2)

  1. ServiceLocator的每个实例都有自己的一些bean缓存(数据源,服务等)。您的ServiceLocator不是单例,因为很少有线程可以轻松创建很少的实例。对于单例实现,您可以使用:

    • synchronized静态方法
    • Pugh的解决方案(嵌套静态类)
  2. 下一个问题是getDataSource()方法。你是对的,很少有线程可以破坏它的实现。甚至服务定位器都是单例,您的缓存上没有同步。每个dataSource都有自己的连接池。因此,您的数据库连接数将会出现问题。

  3. 用户数量取决于数据源的connection count。如果datasource只有一个连接,是的,只允许一个用户。

  4. 解决问题的步骤:

    • 将ServiceLocator设置为singleton或bean缓存为singleton
    • 同步访问缓存
    • 设置可接受的连接数

答案 1 :(得分:1)

1:它是否需要作为单身人士:简而言之,如果您想在其他线程或位置共享它,则为是。单例是一种静态方法。在这种情况下,您甚至可以认为它应该是同步的,尽管有些人更喜欢使用枚举来实现它们以避免需要同步。

原因: servicelocator类是单独的,因此您可以从多个位置调用同一对象上的方法,而无需重新创建它。

使用单例的原因要么是因为构造一个实例需要花费很多资源而不想多次执行它,要么就是因为你想确保在所有对该方法的调用中只使用1个实例。

在这种情况下,它是一个单例,因为servicelocator缓存了名为datasources,当从代码中的任何其他位置调用它时,可以重用它。

但是,你发布的这个单例不是线程安全的。如果你在多线程环境中使用它(比如在应用程序服务器中),那么2个线程可能都试图获得单例。第一个线程可能会获得与缓存不同的单例,而不是第二个。

(第二次和任何后续调用将获得实际的单例实例)。

更糟糕的是,在我看来,内部缓存的访问者代码也不是线程安全的。 这里最糟糕的情况只是你对数据源进行双重查看,并且查找的两个结果之一再次被删除。由于单例的作者使用synchronizedMap,因此get / put是同步的。但 的决定并非如此。这里仍有竞争条件。

2:为什么要放入缓存:

基本上如果你连续几次调用getDataSource(“abc”),只是第一次查找/加载数据源。其他时候代码会在缓存中找到数据源,并直接返回它。

3:好问题:)这取决于你的配置。说不,相对安全,许多用户/线程可以同时访问数据库。

http://docs.oracle.com/javase/7/docs/api/javax/sql/DataSource.html 声明基本数据源仅管理1个连接。使用singleton意味着所有线程可以同时访问同一个数据源,因此如果使用单连接数据源,这将导致麻烦。

然而,数据源最常见的用途是pooleddatasource,它代表一组连接。在这种情况下,从许多位置访问它将为每个单独的线程提供它自己的数据库连接,从而使其安全。当一个线程关闭一个连接时,这将返回到该池的连接以供其他人使用。