Потоки с общим целочисленным объектом не работают должным образом - PullRequest
0 голосов
/ 18 февраля 2019

У меня проблема с печатью чисел в таком формате.

First  1
First  2
Second  3
Second  4
First  5
First  6
Second  7
Second  8
First  9
and so on...

Я реализовал свой работающий интерфейс, как показано ниже.

class ThreadDemo implements Runnable {

 public volatile Integer num;

 public Object lock;

 public ThreadDemo(Integer num, Object lock) {
  this.num = num;
  this.lock = lock;
 }

 @Override
 public void run() {

  try {
   while (true) {
    int count = 0;
    synchronized(lock) {
     Thread.sleep(100);
     while (count < 2) {
      System.out.println(Thread.currentThread().getName() + "  " + num++);
      count++;

     }
     lock.notify();
     lock.wait();
    }
   }
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }
}

Мой основной класс выглядит следующим образом

public class CoWorkingThreads {
 private static volatile Integer num = new Integer(1);
 public static void main(String...args) {
  Object lock = new Object();
  Thread thread1 = new Thread(new ThreadDemo(num, lock), "First");
  thread1.start();
  Thread thread2 = new Thread(new ThreadDemo(num, lock), "Second");
  thread2.start();

 }
}

, когда я запускаю программу, которую я получаювывод выглядит следующим образом:

First  1
First  2
Second  1
Second  2
First  3
First  4
Second  3
Second  4

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

Ответы [ 4 ]

0 голосов
/ 19 февраля 2019

Я все еще считаю, что на этот вопрос НЕ ответили правильно.Недостаток в том, что вы никогда не отмечали общие данные как static.Таким образом, каждый поток имеет свою собственную копию, независимую от другого.Integer - это неизменяемый класс-обертка, который верен, но в этом контексте он не имеет ничего общего.Давайте углубимся в num++.Оператор ++ применяется только к (примитивным) целочисленным типам.За кулисами num распаковывается, применяется ++, и результат затем присваивается обратно num (после преобразования в бокс).Класс Integer не имеет оператора ++.Фактически, Integer объекты являются неизменяемыми.

Неизменяемый означает каждый раз, когда вы увеличиваете и создаете новый объект значения.И этот новый объект значения присваивается вашей ссылке num.Но у двух потоков есть собственная копия ссылки num, указывающая на различные Integer упакованные примитивы.Таким образом, они увеличивают его независимо друг от друга, который не виден другому.Если вы хотите поделиться им между потоками, вы должны использовать static модификатор доступа на сайте объявления.Более того, передача двух значений в общую переменную не имеет смысла.Вместо этого вы можете инициализировать его в строке.Вот исправленная версия.

public class ThreadDemo implements Runnable {
    public static Integer num = 1;

    public static final Object lock = new Object();

    public ThreadDemo() {
    }

    @Override
    public void run() {

        try {
            while (true) {
                int count = 0;
                synchronized (lock) {
                    Thread.sleep(100);
                    while (count < 2) {
                        System.out.println(Thread.currentThread().getName() + "  " + num++);
                        count++;

                    }
                    lock.notify();
                    lock.wait();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class CoWorkingThreads {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new ThreadDemo(), "First");
        thread1.start();
        Thread thread2 = new Thread(new ThreadDemo(), "Second");
        thread2.start();
    }
}

Наконец, использование предоставленного клиентом объекта блокировки нарушает инкапсуляцию политики синхронизации.Поэтому вместо этого я использовал внутренний закрытый объект блокировки.

Вот новый вывод.

Первый 1 Первый 2 Второй 3 Второй 4 Первый 5 Первый 6 Второй 7 Второй 8 Первый 9 Первый10

0 голосов
/ 18 февраля 2019

Java Integer не может быть передан по ссылке.В вашем коде каждый поток создаст копию переменной.Однако atomicInteger может передаваться по ссылке.

Кроме того, чтобы получить правильный результат, вы можете изменить переменную num на статическую переменную.

public static Integer num = 1;

public Object lock;
public ThreadDemo(Integer num, Object lock) {
    //this.num = num;
    this.lock =lock;
}
0 голосов
/ 18 февраля 2019

Насколько вам известно, вместо использования блока synchronized на Object вы можете поэкспериментировать с Lock (s) (например, ReentrantLock) и связанными с ними Condition (s).

Используя Condition (s), вы можете управлять общими ресурсами взаимоисключающим способом между потоками.

0 голосов
/ 18 февраля 2019

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

Подобный вопрос можно найти на SO здесь

...