2013-03-09 3 views
0

Я искал способ использования нескольких потоков и синхронизации. Я пробовал использовать wait() и notify(), но мои потоки по-прежнему не синхронизируются. У меня есть большой проект, но в двух словах мне нужно, чтобы он запускал поток с помощью метода setter (thread1 в этом случае) предопределенное количество раз и после каждого «набора» мне нужен поток с методом getter (thread2)) для запуска и получения объекта. Я рассмотрел многие другие примеры, но я не могу понять, как это работает, поэтому любая помощь или объяснение того, почему это не работает, будет оценена по достоинству.Синхронизированные потоки в 1 классе

Это работает иногда, когда thread1 запускается первым, но в некоторых случаях thread2 запускается первым, поэтому синхронизация не работает.

Спасибо.

import java.util.ArrayList; 

public class ThreadTest{ 

    private ArrayList<Object> myList; 

    public ThreadTest(){ 

     myList = new ArrayList<Object>(); 

     Thread thread1 = new Thread(){ 
      public void run(){ 
       for(int i = 0; i < 10; i++){ 
        addToList("" + i); 
       } 
      } 
     }; 

     Thread thread2 = new Thread(){ 
      public void run(){ 
       for(int i = 0; i < 10; i++){ 
        System.out.print(myList.get(i) + " "); 
       } 
      } 
     }; 

     thread1.start(); 
     thread2.start(); 
    } 

    public synchronized void addToList(String a){ 
     myList.add(a); 
     notify(); 
    } 

    public synchronized ArrayList<Object> getList(){ 
     try{ 
      wait(); 
     } 
     catch (InterruptedException e){ 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     return myList; 
    } 

    public static void main(String[] args){ 
     new ThreadTest(); 
    } 
} 
+0

Какова цель метода getList() '? Вы не используете его. – bsiamionau

+1

Не изобретайте велосипед. Используйте ['BlockingQueue'] (http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html) –

+0

@ bmorris591 Но что, если я хочу квадратное колесо;) –

ответ

2

Используйте BlockingQueue, чтобы сделать ваш Syncronization автомагически, используйте ExecutorService дело со всеми Thread s

public void doStuff() { 
    final Object finishSupplying = new Object(); 
    final BlockingQueue<Object> myList = new LinkedBlockingQueue<Object>(); 
    final Runnable supplier = new Runnable() { 
     public void run() { 
      for (int i = 0; i < 10; i++) { 
       myList.add(i); 
      } 
     } 
    }; 

    final Runnable consumer = new Runnable() { 
     public void run() { 
      while (true) { 
       try { 
        final Object thing = myList.take(); 
        if(thing == finishSupplying) break; 
        System.out.print(thing + " "); 
       } catch (InterruptedException ex) { 
        Thread.currentThread().interrupt(); 
       } 
      } 
     } 
    }; 

    final ExecutorService exectutorService = Executors.newFixedThreadPool(2); 
    final Future<?> supplierHandle = exectutorService.submit(supplier); 
    final Future<?> consumerHandle = exectutorService.submit(consumer); 
    try { 
     supplierHandle.get(); 
    } catch (InterruptedException ex) { 
     Thread.currentThread().interrupt(); 
    } catch (ExecutionException ex) { 
     //PROBLEMS, handle 
    } 
    myList.add(finishSupplying); 
    try { 
     consumerHandle.get(); 
    } catch (InterruptedException ex) { 
     Thread.currentThread().interrupt(); 
    } catch (ExecutionException ex) { 
     //PROBLEMS, handle 
    } 
} 

Убедитесь, что вы shutdown()ExecutorService когда вы сделали в противном случае вы программа не будет выхода.

1

Когда вы сообщаете, вы должны обновить состояние (как есть), которое должно быть проверено в цикле, когда вы ждете. Это необходимо, как

  • Уведомлять запуска перед началом ожидания и сигнал теряется
  • ожидание может разбудить поддельно.

Примечание: ваш потребляющий поток не ждет, потому что вы не вызываете ничего, что ждет.

Существует несколько способов исправить это, но IMHO лучшим решением является использование BlockingQueue, который был разработан для поддержки этого шаблона.

0

Вы не должны использовать getter & setter для доступа ко всему списку, но только для того, чтобы вытаскивать из него элементы. Как было сказано, BlockingQueue - это реализация синхронизированного списка.

Другими словами, если вы хотите реализовать это самостоятельно, замените getList на синхронизированный remove(0) в списке, который возвращает только первый элемент ArrayList.

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