2016-02-05 5 views
-1

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

Вот пример:

public class ThreadHarvest { 
    private static final ReentrantLock lock = new ReentrantLock(); 
    private static boolean safe; 

    public static void main(String[] args) throws InterruptedException 
    { 
     Thread task = new Thread(() ->{ 
      lock.lock(); 
      safe = false; 

      for (long i = 10000000L; i > 0L; --i) 
       System.out.println(i); 

      safe = true; 
      lock.unlock(); 

      System.out.println("Safe ended!"); 
     }); 

     task.start(); 

     while (lock.isLocked() == false); 

     lock.tryLock(5, TimeUnit.SECONDS); 

     if (!safe) 
     { 
      task.stop(); 
      System.out.println("Force ended!"); 
     } 
    } 
} 

Кроме того, существует определенная область, которая гарантированно безопасна, что только после того, как блокировка снимается. И я тоже знаю, что метод остановки устарел, поэтому, если у вас есть хорошие идеи, чтобы сделать его менее склонным к ошибкам, я был бы очень благодарен: D

+0

Примечание: поскольку 'boolean safe' не является изменчивым, ваш основной поток может не увидеть это изменение. –

+2

Синхронизация не является защитой от бесконечных циклов, но это возможный способ преобразования их в блокировки. Ваш вопрос не имеет смысла. – EJP

+0

@PeterLawrey iirc, 'ReentrantLock' также следить за тем, чтобы изменения были видимыми. (вы можете использовать Google для «java reentrantlock memory барьер»). Способ OP, использующий его *, кажется, работает нормально (требуется больше проверки: P) –

ответ

0

Я не совсем понимаю ваш вопрос, но здесь некоторые общие комментарии о вашем коде.

  • У вас никогда не должно быть такой спиновой петли. Я бы добавил Thread.sleep(10); или что-то в этом роде.
  • С замками вы всегда должны положить свою разблокировку в lock; try { } finally { unlock; }. Тогда вы знаете, что ваш замок будет разблокирован, даже если он выдает исключение.
  • Если вы обращаетесь к полю в двух разных потоках, вы должны как-то защитить его. Вы можете использовать AtomicBoolean для safe или пометить его как volatile boolean, иначе главный поток может не увидеть никаких изменений к нему. Нет гарантий синхронизации памяти с isLocked() или tryLock().
  • Вместо вашей блокировки и безопасности, как насчет просто попытки сделать task.join(5, TimeUnit.SECONDS), а затем проверить if (task.isAlive()) { killItWithFire(); }.

Я в настоящее время разрабатывает приложение, которое в некоторых тестовых случаях, идет на бесконечный цикл,

Кажется мне, как вы должны концентрировать свое время решение этой проблемы. thread.stop() - настоящий хак.

+1

одно мнение: оно должно быть 'lock; попробуйте {...} finally {unlock;} 'вместо этого. Вы не хотите разблокировать, если что-то случилось в замке –

+1

Другое дело, я сомневаюсь, что здесь нужно использовать 'AtomicBoolean' или' volatile'. 'ReentrantLock' также служит цели для барьера памяти (так же, как' synchronized') –

+0

Хорошая точка для блокировки @AdrianShum. Исправлена. Безопасный может быть установлен на true _before_! Безопасный тест, который может быть в порядке, но я предпочел бы быть в безопасности, тем более, что 'tryLock (...)' не гарантирует гарантии синхронизации памяти в соответствии с документами, если это не будет успешным. – Gray