2013-10-02 2 views
1

У меня есть приложение, которое выполняет два потока параллельно, каждый из которых выполняет какое-то действие, которое в конце приводит к получению целого числа. В моем основном потоке я хотел бы выполнить некоторую операцию над int, создаваемую каждым Thread A и Thread B (назовите их int a и int b соответственно), а затем выведите их в том порядке, в котором каждый поток выплевывает их. Поэтому, по сути, я выполняю каждый поток через регулярные интервалы (скажем, каждые 2 секунды), и каждый из потоков выплескивает целое число, которое я манипулирую и распечатываю в порядке их разбиения.Очередь для сбора выходов из потоков

Для этого, как я могу объединить данные для каждого потока, который должен быть напечатан потоком gui? Могу ли я использовать очередь для каждого потока, который наблюдается в основном потоке, и когда он обновляется, главный gui манипулирует и выводит их? Как я могу написать такую ​​очередь?

Код для моей нити следующим образом:

Timer timer = new Timer(); 
timer.scheduleAtFixedRate(new TimerTask() { 
    @Override 
    public void run() { 
     new Thread(new t1()).start(//TODO: pass in some parameter that this 
            //thread will write to); 
     new Thread(new t2()).start(); 
    } 
}, 0, period); 
+0

Очередь, ожидание() и уведомление(). Это ваши ключевые слова. У меня нет времени разрабатывать, извините. – RaphMclee

ответ

1

Рассмотрите этот вариант, это может быть полезно. Он использует ConcurrentLinkedQueue для потокобезопасных операций в очереди.

final Queue<Integer> queue1 = new ConcurrentLinkedQueue<Integer>(); 
final Queue<Integer> queue2 = new ConcurrentLinkedQueue<Integer>(); 

final Random r = new Random(); 

Timer timer = new Timer(); 
timer.scheduleAtFixedRate(new TimerTask() {    
    @Override 
    public void run() { 
     //Thread 1 
     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       //even numbers 
       queue1.add(r.nextInt(50)*2); 
      } 
     }).start(); 

     //Thread 2 
     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       //odd numbers 
       queue2.add(r.nextInt(50)*2 + 1); 
      } 
     }).start(); 
    } 
}, 0, 2000); 

//Main thread (maybe GUI) 
while (true){ 
    while (!queue1.isEmpty()){ 
     System.out.println("Thread-1: " + queue1.poll()); 
    } 
    while (!queue2.isEmpty()){ 
     System.out.println("Thread-2: " + queue2.poll()); 
    } 
} 

Редактировать

Что вам действительно нужно, это производитель-потребитель (см http://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem). Чтобы решить эту проблему, мы будем использовать другую очередь ArrayBlockingQueue, потому что эта структура данных позволяет нам блокировать до тех пор, пока что-то не будет (или не использовано).

final BlockingQueue<Integer> queue1 = new ArrayBlockingQueue<Integer>(1024); 
final BlockingQueue<Integer> queue2 = new ArrayBlockingQueue<Integer>(1024); 

final Random r = new Random();   

Timer timer = new Timer(); 
timer.scheduleAtFixedRate(new TimerTask() { 
    @Override 
    public void run() { 
     try { 
      //don't create threads here, this is already a thread, just produce the numbers 
      //If the queue is full `BlockingQueue.put()` will block until the consumer consume numbers. 

      //Producer even number 
      queue1.put(r.nextInt(50)*2); 

      //Producer odd number 
      queue2.put(r.nextInt(50)*2 + 1); 

     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
}, 0, 2000); 

//Now we create the threads that will take numbers from the producer. Don't worry about the `while (true)`, it is not wasting resources because `BlockingQueue.take()` will block the thread until something is produced. 

//Consumer 1 
new Thread(new Runnable() { 
    @Override 
    public void run() { 
     try { 
      while (true){ 
       System.out.println("Thread-1: " + queue1.take()); 

       //Or update some UI component 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
}).start(); 

//Consumer 2 
new Thread(new Runnable() { 
    @Override 
    public void run() { 
     try { 
      while (true){ 
       System.out.println("Thread-2: " + queue2.take()); 

       //Or update some UI component 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
}).start(); 
+0

Дело в том, что таймер не имеет прямого доступа к очереди изнутри run(). очередь находится в другом классе. Так что я могу просто передать его, и когда я добавлю в run(), очередь в другом классе также увидит, что он добавится. другими словами, была бы очередь, пройденная ref? –

+0

@JohnBaum Доступ к очереди - это еще одна вещь, вы можете сделать это так, как вы предпочитаете. Для демонстрационных целей я использую конечную переменную, но у вас может быть одноэлемент, вызов геттера из объекта и т. Д. – omainegra

+0

- это время (правда), единственный способ проверить, доступны ли новые данные очереди? Есть ли система, основанная на уведомлении, которую я могу использовать, которая не блокирует ui? –

1

Попробуйте использовать Executor структуру, которая использует Callables вместо Runnables. Одним из преимуществ использования Callable является то, что он предоставляет метод call, аналогичный методу Runnable run, но метод call может return значение. Таким образом, в вашем случае вы можете вернуть целочисленные значения из двух ваших потоков, а затем можете использовать их в своем основном потоке.

0

Передайте очередь на конструктор обоих потоков.

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

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