Поочередная запись потоками в файл

141
21 мая 2022, 13:50

Всем привет, есть задание:
На вход передается целое число, больше 0, кратное 2 (n). Создается два потока, работающих параллельно, каждый поток в цикле, считывает значение из файла out.txt увеличивает его на 1, выводит в консоли старое значение, новое значение и идентификатор потока (идентификатор может быть произвольным), и записывает обратно в файл. В конечном итоге оба потока должны успешно завершить свою работу, и в консоль должно вывестись содержимое файла out.txt (которое должно быть равно заданному на входе n).
Пытаюсь сделать так:

private static final Semaphore semaphore = new Semaphore(1);
public void execute() {
    threadOne.start();
    threadTwo.start();
} 
private void task() {
    try {
        semaphore.acquire();
        while (incrementValue()) {
            incrementValue();
            semaphore.release();
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private boolean incrementValue() {
    try {
        Scanner reader = new Scanner(new FileReader(FILE_NAME));
        int value = Integer.parseInt(reader.nextLine());
        if (value == n) {
            return false;
        }
        FileWriter writer = new FileWriter(FILE_NAME);
        writer.write(String.valueOf(value + 1));
        System.out.printf("Thread: %s, old - %d, new - %d", Thread.currentThread().getName(), value, ++value);
        System.out.println();
        writer.flush();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return true;
}

В итоге на выходе получается это:

Thread: Thread-0, old - 0, new - 1
Thread: Thread-0, old - 1, new - 2
Thread: Thread-0, old - 2, new - 3
Thread: Thread-1, old - 2, new - 3
Thread: Thread-0, old - 3, new - 4
Thread: Thread-1, old - 3, new - 4

Как сделать так, чтобы потоки поочередно записывали в файл? Заранее благодарю за помощь.

Answer 1

Сразу целая куча проблем:

  1. семафор захватываете перед циклом, а отпускаете внутри. После первой итерации семафор отпущен, а поток продолжает себе работать с файлом. Нужно захватывать один раз в начале тела цикла.
  2. За одну итерацию метод incrementValue вызывается два раза. Сначала в условии цикла while и еще раз в теле. Делайте раз в теле и присваивайте переменной, которую и проверяйте в условии.
  3. Файлу после записи нужно не просто flush делать, а полностью закрывать. Пользуйтесь try-with-resources

Вот так (плюс изменения по работе с файлами) работает лучше:

boolean toContinue = true;
while (toContinue) {
    semaphore.acquire();
    toContinue = incrementValue();
    semaphore.release();
    Thread.sleep(1);  // см. пояснения ниже 
}

Строка с sleep необязательна, но дело в том, что после отпускания семафора JVM необязательно отдаст управление другому потоку. Переключение между потоками довольно накладная операция и поэтому слишком часто JVM ее не делает. При малых значениях n квант времени выделенный для выполнения первому потоку может и не завершиться и тогда он опять захватит семафор. На моей системе один поток успевает сделать около 200 переключений, пока планировщик не отдаст управление другому потоку (это если без sleep). sleep же (немного) уравнивает шансы, т.е. это сигнал планировщику, что данный поток хочет отдать управление. (Также можно использовать Thread.yield() или Thread.sleep(0), но с ними тот же поток чаще продолжает выполнение по крайне мере у меня на системе).

READ ALSO
Как получить такой эффект

Как получить такой эффект

Подскажите, как получить такой эффект:

324
Как правильно задать высоту экрана?

Как правильно задать высоту экрана?

При тестовом просмотре сайта на ноуте, выдало вот такую дичьПодскажите, как правильно рассчитывать высоту экрана, чтобы смотрелось хорошо...

241
Как работать с DOM без шаблонизаторов?

Как работать с DOM без шаблонизаторов?

Хочу получить значение со страницы из input при помощи python, но куда ни глянь - везде используют Django или Jinja2Можно ли как-то обойтись без них?

310
как написать media в перевернутом виде в bootstrap 4?

как написать media в перевернутом виде в bootstrap 4?

как написать media в перевернутом виде в bootstrap 4? col-12 col-sm-6 col-md-3 так сделал но sm в перевернутом виде не поддерживает

422