2014-10-16 4 views
0

Я унаследовал этот код от предыдущего разработчика (lol). Я планирую изменить это, чтобы поддерживать соединение, вместо того, чтобы использовать обратный вызов слушателя.Singleton with Listener versus Join

Мои требования: 1. Мне нужно, чтобы вызывающий поток дождался завершения потока класса DoMath. 2. Мне нужно, чтобы другие потоки не вызывали его.

Это, в другом потоке (и класс) -:

DoMath.getInstance().performMathCalc(); 

Это не ждать или сна, конечно, когда он называет это:

public class DoMath { 
    protected math calc() { 
    } 

    public static DoMath getInstance() { 
     if(_instance == null) { 
      _instance = new DoMath(); 
     } 

     return _instance; 
    } 

    // perform a synchronous math calc, and return a boolean indicating success or failure. 
    public boolean performMathCalc() { 
     MathEngine.setApplicationMode(MathEngine.AUTO); 
     MathEngine.getInstance().StartMathCalc(MathEngine.DIVISION); 
     return true; 
    } 

    // perform an async math calc, and call back the listener when done 
    public void performMathCalc(final listener client) { 
     Thread mathThread = new Thread(new Runnable() { 
      public void run() { 
       boolean result = performMathCalc(); 
       client.mathFinished(result); 
      } 
     }); 
     mathThread.setDaemon(true); 
     mathThread.start(); 
    } 

    public static interface listener { 
     public void mathFinished(boolean success); 
    } 

    protected static DoMath _instance; 
} 

Таким образом, это лучше всего использовать слушателя или реализовать соединение в вызывающем классе?

+1

не ждите, не спящий, не присоединяйте и не блокируйте основную нить. Когда-либо. – njzk2

+0

@ njzk2 Хороший совет, если вы измените «когда-либо» на «при выполнении операции, рекламируемой как * асинхронная *» (что в данном случае обязательно применяется). –

+0

Также обратите внимание, что код aysnc имеет, вероятно, ошибку. Слушатель не будет возвращен в поток, который вызывается executeMathCalc, но вместо этого в фоновом потоке. – cyngus

ответ

1

Мне нужно, чтобы вызывающий поток дождался завершения потока класса DoMath.

У вас уже есть это. Обратите внимание, как есть дваperformMathCalc методы:

  1. Первый метод не принимает никаких аргументов и выполняет вычисление на нити вызывающего абонента, а затем возвращает результат. Это соответствует вашему первому требованию.

  2. Второй способ - асинхронная обертка для первого; он позволяет вызывающему пользователю начать вычисление, а затем уйти с кем-то еще с пониманием того, что в какой-то момент в будущем кто-то будет уведомлен о завершении операции. Это полезная функциональность, поэтому я бы сохранил ее.

я вижу одну проблемы с асинхронной оберткой, однако: слушатель не будет уведомлен в том случае, если метод ядра performMathCalc() генерирует исключение. Рассмотрите возможность использования блока try/catch/finally, чтобы гарантировать, что слушатель всегда получает уведомление, даже если возникает ошибка. Вам нужно будет решить, следует ли добавить второй обратный вызов к вашему слушателю (например, mathFailed) или просто вызвать mathFinished(false) об ошибках.

Мне нужно, чтобы другие потоки не вызывали его.

Мы можем выполнить это достаточно легко, и поскольку асинхронная версия просто делегирует синхронную версию, нам нужно только заблокировать синхронную версию. Самый простой способ будет отмечать метод как synchronized, так как ваш класс обеспечивает только одну логическую функцию:

public synchronized boolean performMathCalc() { 
    MathEngine.setApplicationMode(MathEngine.AUTO); 
    MathEngine.getInstance().StartMathCalc(MathEngine.DIVISION); 
    return true; 
} 

В качестве альтернативы, если вы в конечном итоге продлив DoMath класс для выполнения других видов работ, которые не являются взаимоисключающими, вы можете синхронизировать блокировки, зависящие от конкретной операции.

Это оставляет нас с одноплодным аксессором:

public static DoMath getInstance() { 
    if (_instance == null) { 
     _instance = new DoMath(); 
    } 
    return _instance; 
} 

Этой условная инициализация не потокобезопасный. Ваш синглтон очень прост и не имеет начальных затрат на инициализацию, поэтому просто отметьте _instance как final static и инициализируйте его в объявлении.

+0

Я поддержал все три - потому что у каждого были значительные вылазки, которые я мог использовать. Мне было интересно, если это потокобезопасно, теперь я знаю, что это не так. Я не знал, что объединение более или менее превратилось в обработку изображений uhhmmmm ios (непредсказуемо без толчка). Спасибо за это. Переход с обратными вызовами в конечном статическом экземпляре. СПАСИБО!!! (Удивлены, что на этом не было никаких повышений, но, на мой взгляд, ваши ответы были ответом. Спасибо еще раз!) –

1

Вы действительно хотите приостановить свою нить до тех пор, пока не закончите другую? Вы никогда не должны блокировать основной поток.

The join method allows one thread to wait for the completion of another. If t is a Thread object whose thread is currently executing, 

t.join(); 
causes the current thread to pause execution until t's thread terminates. Overloads of join allow the programmer to specify a waiting period. However, as with sleep, join is dependent on the OS for timing, so you should not assume that join will wait exactly as long as you specify. 

(от ява Docs)

Кроме того, не performMatchCalc() должен быть публичным?

Теперь, на первый взгляд, этот код действительно выглядит правильно, но вы все равно можете помешать кому-то начать другой расчет. Может быть, с чем-то подобным этому:

public class DoMath { 
     private Thread mathThread; 

     protected math calc() { 
     } 

     public static DoMath getInstance() { 
      if(_instance == null) { 
       _instance = new DoMath(); 
      } 

      return _instance; 
     } 

     // perform a synchronous math calc, and return a boolean indicating success or failure. 
     public boolean performMathCalc() { 
      if(null != mathThread && mathThread.isAlive()) 
       return false; 

      MathEngine.setApplicationMode(MathEngine.AUTO); 
      MathEngine.getInstance().StartMathCalc(MathEngine.DIVISION); 
      return true; 
     } 

     // perform an async math calc, and call back the listener when done 
     public void performMathCalc(final listener client) { 
      //re-start calculation? if so 
      if(null != mathThread && mathThread.isAlive()) { 
       matchThread.interrupt(); 
       matchThread = null; 
      } 


      mathThread = new Thread(new Runnable() { 
       public void run() { 
        boolean result = performMathCalc(); 
        client.mathFinished(result); 
       } 
      }); 
      mathThread.setDaemon(true); 
      mathThread.start(); 
     } 

     public static interface listener { 
      public void mathFinished(boolean success); 
     } 

     protected static DoMath _instance; 
    } 
1

Обратите внимание, что это:

public static DoMath getInstance() { 
    if(_instance == null) { 
     _instance = new DoMath(); 
    } 

    return _instance; 
} 

не поточно-. Чтобы убедиться, что ваш класс действительно является Singleton (относительно ClassLoader), вы должны либо синхронизировать этот метод, либо инициализировать член _instance в его объявлении. В любом случае, _instance должно быть private или final или оба.

Что касается ваших фактических потребностей,

(1) кажется, что вы хотите изменить либо асинхронный вызов в синхронную или поставить синхронную обертку вокруг него. Вы можете использовать последнее через существующий интерфейс прослушивателя, который сохранил бы способность выполнять асинхронные задания. Если вы не хотите, чтобы вместо того, чтобы присоединяться, пропустите запуск нового потока: просто запустите вычисление в текущем потоке.

(2) Как вы можете предотвратить одновременное выполнение нескольких потоков из-за того, что частично зависит от того, как вы решаете проблему (1). Если вы сделаете все синхронно, вы можете просто сделать DoMath.performMathCalc() синхронизированным методом. Если вы сохраните параметр асинхронного вычисления, вы можете посмотреть на пакет java.util.concurrent.locks для классов, которые могут вам помочь.