Странная проблема с простой многопоточной программой на Java - PullRequest
3 голосов
/ 16 января 2011

Я только начинаю играть с многопоточным программированием.Я хотел бы, чтобы моя программа показала поочередно символы '-' и '+', но это не так.Моя задача - использовать ключевое слово synchronized.Насколько я имею:

class FunnyStringGenerator{

    private char c;

    public FunnyStringGenerator(){
        c = '-';
    }

    public synchronized char next(){

        if(c == '-'){
            c = '+';
        }
        else{
            c = '-';
        }

        return c;
    }
}

class ThreadToGenerateStr implements Runnable{

    FunnyStringGenerator gen;

    public ThreadToGenerateStr(FunnyStringGenerator fsg){
        gen = fsg;
    }

    @Override
    public void run() {
        for(int i = 0; i < 10; i++){

            System.out.print(gen.next());
        }
    }


}

public class Main{


    public static void main(String[] args) throws IOException {

        FunnyStringGenerator FSG = new FunnyStringGenerator();

        ExecutorService exec = Executors.newCachedThreadPool();

        for(int i = 0; i < 20; i++){
            exec.execute(new ThreadToGenerateStr(FSG));
        }

    }

}

РЕДАКТИРОВАТЬ: Я также тестирую Thread.sleep в методе запуска вместо for цикл.

Ответы [ 3 ]

5 голосов
/ 16 января 2011

Ваш synchronized блок в FunnyStringGenerator.next() работает нормально.Он будет возвращать '+' и '-' поочередно.

Однако у вас есть условие гонки в ThreadToGenerateStr.run():

System.out.print(gen.next());

Это эквивалентно:

char c = gen.next(); // Synchronized
System.out.print(c); // Not synchronized

Проблема возникает, когда:

  • Поток 1 вызывает gen.next (), получая результат '-'
  • Поток 2 вызывает gen.next (), получая результатиз '+'
  • Поток 2 вызывает System.out.print (), запись '+'
  • Поток 1 вызывает System.out.print (), запись '-'

В результате '+' и '-' записываются в противоположном порядке.

Существуют различные возможные обходные пути, например:

  • Вызовите оба поколения.next () и System.out.print () в одном блоке synchronized (как в ответе собачьей упущенности)
  • Заставьте gen.next () записать символ в поток вместо его возврата
  • Сделайте, чтобы gen.next () добавлял символ к общему BlockingQueue и имел выделенный поток ввода-вывода, берущий символы из этой очереди и печатавший их.
3 голосов
/ 16 января 2011

Вместо синхронизации метода сделайте следующее:

        synchronized (gen) {
            System.out.print(gen.next());
        }

Вам нужно обернуть весь оператор печати в синхронизированный блок, чтобы другой поток не мог изменить значение c до его печати. ​​

Думайте об этом как о двух утверждениях:

char n = gen.next();
System.out.print(n);
0 голосов
/ 16 января 2011

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

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