Почему этот код не является потокобезопасным, хотя AtomicInteger используется для отслеживания прогресса? - PullRequest
1 голос
/ 26 апреля 2019

Я попытался создать класс, который расширяет поток, который просто принимает массив строк и печатает первые 2 строки попеременно для 10000 итераций. Я отслеживаю индекс для печати от использования AtomicInteger (счетчик), однако вывод иногда печатает это: Привет Привет Привет вес Привет Привет и т.п. вместо чередования на каждой итерации. Почему это так, и как я могу это исправить, не добавляя синхронизированный метод run?

public class MyThreadDelegate implements Runnable {

  List<String> words;
  AtomicInteger counter = new AtomicInteger(0);

  public MyThread(List<String> words) {
    this.words = words;
  }

  @Override
  public void run() {
    for (int i = 0; i < 10000; i++) {
      System.out.println(words.get(counter.getAndIncrement()%2) + counter.get());
    }
  }

  public static void main(String[] args) {

    MyThreadDelegate myThreadDelegate = new MyThreadDelegate(Arrays.asList("hello", "w"));

    Thread t1 = new Thread(MyThreadDelegate);
    Thread t2 = new Thread(MyThreadDelegate);

    t1.start();
    t2.start();
  }
}

1 Ответ

0 голосов
/ 26 апреля 2019

Пока числа извлекаются одно за другим, остальная часть метода не синхронизируется.Поэтому иногда это может происходить:

  • t1: получает значение 0 от счетчика
  • t2: получает значение 1 от счетчика
  • t2: печатает w
  • t1: печатает привет

Быстрое решение состоит в том, чтобы поместить всю строку System.out в блок synchronized, но это не гарантирует, что потоки сменяются.Это просто гарантирует, что значение echt будет извлечено, увеличено и распечатано до следующего.

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

EDIT: также, вы, вероятно, должны иметь MyThread, реализующий Runnable вместо расширения Thread, если вы собираетесь использоватьэто так.См. Эту ссылку для получения дополнительной информации: https://www.baeldung.com/java-runnable-vs-extending-thread (Соломон Слоу избил меня до этого:)

...