2012-01-17 80 views
3

我有包含就像一個單身靜態字段類:如何同步超類的靜態字段上的訪問?

public class A { 

    private static MyAPI instance = null; 

    protected synchronized static MyAPI getAPI() throws Exception { 
     if (instance == null){ 
      // init API; 
     } 
     return instance; 
    } 

    // other methods 

} 

而且我有多個類從A類繼承和需要執行的API操作。我在多線程環境中工作,API可以一次工作一次,所以我必須確保所有的子類不能同時在API上工作。要做到這一點,當我訪問子類的API同步I超類:

public class B extends A { 

    public void myMethod(){ 
     synchronized (A.class) { 
      myAPI = getAPI(); 
      // do stuffs with myAPI 
     } 
    } 
} 

有了這個解決方案,我鎖定整個類,而不是僅僅的API實例,所以我的A類的其他方法都沒有當一個子類在API上工作並且可以減少性能時可用。

您認爲這是最好的解決方案還是您知道更好的方法?

謝謝。

回答

1

如果你不想鎖定整個類,你可以鎖定您在該方法只使用一個靜態對象:

public class A { 

    private static MyAPI instance = null; 
    protected static Object lockForMyMethod = new Object(); //have a static lock 

    // other methods  
} 

public class B extends A { 

    public void myMethod(){ 
     synchronized (A.lockForMyMethod) { //do not lock on A.class 
      myAPI = getAPI(); 
      // do stuffs with myAPI 
     } 
    } 
} 
2

有,我會考慮在這裏兩個問題:

  1. 首先,因爲MyAPI對象充當單,事實上其他類從A類繼承是無關緊要的。你也許只需要在非分層結構中的其他類引用單例。其次,同步應該在MyAPI的代碼中完成,這樣你就可以用任何你想要的方式來控制同步粒度。這可以讓你實現更好的封裝,而且你不需要擔心在繼續之前忘記獲取鎖的壞行爲的調用者。它可以是每方法,每功能性等

例如:

class MyAPI { 

    public synchronized void doWork1() { // class level lock 
    ... 
    } 

    public void doWork2 { 
    synchronized (someLockObject) { 
     ... 
    } 
    } 

    public void doWork3 { // related to doWork2, lock the same object 
    synchronized (someLockObject) { 
     ... 
    } 
    } 
+0

我同意第二點,但我不能修改API,因爲它不是我的! – alex88 2012-01-17 15:41:46

+1

然後用一個裝飾器包裝它 - 另一個單獨:) – Yoni 2012-01-18 07:24:41

0

我在多線程環境中工作,並且所述API可以一次使用一次,所以我必須確保所有子類不能同時在API上工作。

根據您的環境,考慮使用ExecutorService

例如:您可以使用固定線程池大小爲1的ThreadPoolExecutor並將您的作業提交給該執行程序。

這樣,您可以確保您的API僅在您提交的Callable的call()方法中使用。 由於您只有一個線程可以工作,因此您不必擔心API的併發訪問。

同樣,我不知道你正在工作的環境,所以也許這是一個壞主意或簡單的不可能解決與ExecutorService的問題。

+0

這對我想要做的事有點複雜,但根本不是一個壞主意! – alex88 2012-01-17 15:44:37