2012-01-17 2 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 

} 

И у меня есть несколько классов, которые наследуют от класса А и необходимых для выполнения действий по API. Я работаю в многопоточной среде, и API может работать один раз за раз, поэтому я должен гарантировать, что все подклассы не будут работать в API одновременно. Чтобы сделать это, я синхронизировать суперкласс, когда я получить доступ к API в подклассы:

public class B extends A { 

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

С помощью этого решения, я заблокировать весь класс вместо всего экземпляра API, так что другие методы моего класса А не доступный, когда подкласс работает над 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 
     } 
    } 
} 
1

Не знаете, почему вам нужно блокировать каждый доступ к вашему статическому члену, но подумайте об использовании AtomicReference and it's getAndSet() method для лучшей производительности.

+0

Существует нулевая потребность в * AtomicReference * здесь. – TacticalCoder

2

Есть два вопроса, которые я бы рассмотреть здесь:

  1. Во-первых, потому что MyAPI объект действует как синглтон, тот факт, что другие классы наследуют от класса A не имеет значения. Вы могли бы просто иметь другие классы в неиерархической структуре, относящиеся к singleton.

  2. Во-вторых, синхронизация должна выполняться внутри кода 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

+1

Затем оберните его декоратором - еще один синглтон :) – Yoni

0

я работать в многопоточной среде и API, может работать один раз в то время, так что я должны гарантировать, что все подклассы не будут работать в API одновременно.

В зависимости от вашей среды, рассмотрите возможность использования ExecutorService.

Например: вы можете использовать ThreadPoolExecutor с фиксированным размером пула потоков 1 и отправить свои задания этому исполнителю.

Таким образом, вы можете гарантировать, что ваш API используется только в методе call() вызываемого вами сообщения. Поскольку у вас работает только один поток, вам не нужно беспокоиться о параллельном доступе API.

Опять же, я не знаю среды, в которой вы работаете, возможно, это плохая идея или просто невозможно решить проблему с помощью ExecutorService.

+0

Это немного сложно для того, что я хочу сделать, но это совсем не плохая идея! – alex88

Смежные вопросы