2011-01-16 4 views
3

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

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)); 
     } 

    } 

} 

EDIT: Я также тестирование Thread.sleep в методе выполнения вместо for цикла.

ответ

5

Ваш 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. Следующий(), получая результат '+'
  • Thread 2 вызовы System.out.print(), написание '+'
  • тему 1 вызовы System.out.print(), написание '-'

В результате буквы «+» и «-» написаны в обратном порядке.

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

  • вызовов и gen.next() и System.out.print() в одном synchronized блоке (как в ответ кендырь в)
  • сделать ген. next() записать символ в поток, а не возвращать его
  • Сделайте gen.next() добавьте символ в общий BlockingQueue и выделите выделенную цепочку ввода-вывода из этой очереди и распечатайте ее.
3

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

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

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

Думай о нем, как два заявления:

char n = gen.next(); 
System.out.print(n); 
-1

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

+0

Заботьтесь о том, почему голосует. –

Смежные вопросы