从另一个类访问的Singleton类

时间:2012-10-17 17:11:01

标签: java multithreading singleton

我有一个场景,我必须连接到虚拟中心并获取数据。我已经实现了一个单例类,因此两个线程不能同时访问VC,因为它给出了并发访问问题。我的代码如下:

public class Connector {    
private static Connector instance ;    
private Connector(String urlStr, String username, String password) {
    connect(urlStr, username, password);
}    
public static synchronized Connector getInstance(String urlStr, String username, String password) {
    if (instance == null){
        instance = new Connector(urlStr,username,password);
        System.out.println("creating instance");
    }
    return instance ;
}   
public void connect(String urlStr, String username, String password) {
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    try {
        //code to connect to VC
        }

    } catch (RuntimeException e) {
        connectException = e;
    } finally {
        Thread.currentThread().setContextClassLoader(cl);
    }
}


public void disconnect() throws RuntimeFault, RemoteException {
    //code for disconnect
    }
}

}

我通过以下方式从另一个类调用它:

Connector c = Connector.getInstance(dburl, dbuser, dbpass);
c.connect(dburl, dbuser, dbpass);
//code for getting data
c.disconnect();

现在,如果我有2个同时请求从病毒中心获取数据,其中一个请求失败,说“会话未经过身份验证”。 你能帮助我们更好地解决这个问题吗? 并且由于始终使用相同的实例,我们如何区分它是否是一个不同的虚拟中心。

2 个答案:

答案 0 :(得分:0)

你的序列

  1. 连接
  2. 做东西
  3. 断开
  4. 不是原子,这意味着可能

    1. 线程1连接
    2. 线程2连接
    3. 线程1做东西
    4. 线程1断开连接
    5. 线程2尝试做事并失败。

    6. 构建您的类,以便客户端无法连接,无法断开连接或将操作与其他操作交错。

      您的API可能允许希望使用连接的代码在连接时传入使用连接的对象,并返回使用该连接的结果:

       public interface ConnectionTask<T> {
         public T useConnection(Connection c);
       }
      

      然后代替getInstance写一个<{p}的useConnection

       public synchronized <T> T useConnection(ConnectTask<T> c) {
         connect();
         try {
           return c.useConnection(this);
         } finally {
           disconnect();
         }
       }
      

      并制作connectdisconnect private,以便客户不会滥用它们。

答案 1 :(得分:0)

您只能在第一种方法中保留对连接的独占访问权。

我建议你添加一个Lock,例如你在第一种方法中锁定的ReentrantLock,并在你释放连接时解锁。

另一种方法是使用可能更安全的访客模式。

interface UsesConnector {
    public void useConnector(Connector connector);
}

public class Connector {
    private static final Connector connector = new Connector();

    public static synchronized void useConnector(String urlStr, String username, String password, UsesConnector usesConnector) {
         connector.connect(urlStr, username, password);
         try {
             usesConnector.useConnector(connector);
         } finally {
             connector.disconnect();
         }
    }
}