2012-10-17 88 views
2

我有一個場景,我必須連接到虛擬中心並獲取數據。我實現了一個單例類,以便兩個線程不能同時訪問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個同時請求獲得來自viruatal中心的數據,其中一人失敗說「會話未通過身份驗證」。 你能幫助我們以更好的方式來處理這個問題嗎?因爲總是使用相同的實例,我們如何區分不同的虛擬中心。

+1

你做得完全錯誤,不要使用單身,如果你不能 –

+0

換句話說就是@RomanC說的。 –

+0

閱讀:https://sites.google.com/site/steveyegge2/singleton-considered-stupid –

回答

0

你的序列

  1. 連接
  2. 做的東西
  3. 斷開

不是原子,這意味着它有可能

  1. 線程1連接
  2. 線程2連接
  3. 線程1做的東西
  4. 線程1斷開
  5. 線程2次嘗試做的東西和失敗。

結構類以便客戶端無法連接失敗,不能斷開,或與另一交錯操作。

你的API可以使想要使用一個連接在使用,而它連接的連接對象通過,並返回使用該連接的結果代碼:

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

,然後代替getInstanceuseConnection,做

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

,使connectdisconnectprivate,使客戶端不能濫用它們。

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(); 
     } 
    } 
}