Провоцирование состояния гонки на Яве - PullRequest
7 голосов
/ 16 сентября 2011

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

Код выглядит примерно так:

class MyDateTime {
  String getColonTime() {
    // datetime is some kind of lazy caching variable declared somewhere(does not matter)
    if (datetime == null) {
      initDateTime(); //Uses lazy to initlialize variable, takes some time
    }
    // Colon time stores hh:mm as string
    if (datetime.colonTime == null) {
      StringBuilder sb = new StringBuilder();
      //Now do some steps to build the hh:mm string
      //...
      //set colon time
      datetime.colonTime = sb.toString();
    }
  return datetime.colonTime;
  }
}

Объяснение: initDateTime назначает новыйэкземпляр для dateTime, поэтому datetime.colonTime впоследствии будет нулевым (поскольку мы хотим инициализировать его как ленивый, как я уже говорил ранее).Теперь, если поток A входит в метод, а затем планировщик останавливает его непосредственно перед тем, как он сможет запустить initDateTime ().Поток B теперь выполняет getColonTime (), видит, что datetime по-прежнему равен нулю, и инициализирует его.datetime.colonTime имеет значение null, поэтому второй блок if выполняется, и datetime.colonTime получает значение StringBuilder.Если тогда планировщик останавливает поток между этой строкой и оператором return и возобновляет поток A, происходит следующее: поскольку A был остановлен непосредственно перед вызовом initDateTime, A теперь вызывает initDateTime (), что будет своего рода reset объект datetime, снова устанавливающий значение datetime.colonTime в null.Затем поток A войдет во второй блок if, но планировщик прервет A до datetime.colonTime = sb.toString ();называется.В заключение, dateTime.colonTime по-прежнему равен нулю.Теперь планировщик возобновляет работу B, а метод возвращает значение NULL.

Я попытался спровоцировать состояние гонки, используя несколько потоков, вызывающих getColonTime () для одного (конечного) экземпляра MyDateTime, но в некоторых случаях это не удается.крайне редкие случаи :( Есть какие-нибудь подсказки, как написать "тест" JUnit?

Ответы [ 3 ]

7 голосов
/ 16 сентября 2011

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

5 голосов
/ 16 сентября 2011

Вы можете посмотреть на Thread Weaver , или могут быть другие платформы для тестирования многопоточного кода. Я не использовал его, но Руководство пользователя выглядит так, как будто оно предназначено именно для этого типа тестирования.

1 голос
/ 21 апреля 2016

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

В вашем случае я бы сделал что-то вроде

    class MyDateTime {
        String getColonTime() throws InterruptedException{
           if (datetime == null) {
              Thread.sleep(new Random().nextInt(100); //Wait  to enhance the chances that multiple threads enter here and reset colonTime.
              initDateTime(); 
           }
           Thread.sleep(new Random().nextInt(100); //Wait  to enhance the chances that colonTime stays null for a while.
           if (datetime.colonTime == null) {
              StringBuilder sb = new StringBuilder();
              datetime.colonTime = sb.toString();
           }
           Thread.sleep(new Random().nextInt(100); //Wait to favour reset of colonTime by another thread in the meantime.
           return datetime.colonTime;
        }
    }

Но, очевидно, это довольно быстро становится грязным.Хотелось бы, чтобы был какой-то способ заставить планировщик исследовать все пути с некоторыми «точками останова».

Поскольку пост немного устарел, мне было интересно, нашли ли вы хорошие способы для тестирования условий гонки в Java,Любой совет, чтобы поделиться?

Спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...