2013-07-15 7 views
0

Я написал фрагмент кода, который запускает два потока; один поток печатает все нечетные числа, а другой поток печатает все четные числа. Я использовал комбинацию встроенных команд блокировки и связи потоков для обеспечения правильного чередования двух моих потоков. Вот мой код,Два потока, два синхронизированных блока и один встроенный замок

public class threadEvenOdd implements Runnable 
{ 
    static Boolean isOdd=true; 
    int count = 10; 
    Boolean value; 
    static int c=1; 
    static Object lock = new Object(); 

    threadEvenOdd(Boolean temp) 
    { 
     value = temp; 
    } 
    public void run() 
    { 
     if(value) 
     { 
      printOdd(count); 
     } 
     if(!value) 
     { 
      printEven(count); 
     } 
    } 
    void printOdd(int count) 
    { 
     try 
     { 
      for(int i=0;i<count/2;i++) 
      { 
       //System.out.println("odd enters lock"); 
       synchronized(lock) 
       { 
        if(!isOdd) 
        { 
         //System.out.println("odd in barrier"); 
         lock.wait(); 
        } 
        System.out.println(c); 
        c++; 
        isOdd = false; 
        //System.out.println("odd notifies"); 
        lock.notify(); 
       } 
      } 
     } 
     catch(Exception e) 
     { 
      System.out.println(e); 
     } 
    } 
    void printEven(int count) 
    { 
     try 
     { 
      for(int i=0;i<count/2;i++) 
      { 
       //System.out.println("even enters lock"); 
       synchronized(lock) 
       { 
        if(isOdd) 
        { 
         //System.out.println("even in barrier"); 
         lock.wait(); 
        } 
        System.out.println(c); 
        c++; 
        isOdd = true; 
        //System.out.println("even notifies"); 
        lock.notify(); 
       } 
      } 
     } 
     catch(Exception e) 
     { 
      System.out.println(e); 
     } 
    } 
    public static void main (String args[]) 
    { 
     threadEvenOdd th1 = new threadEvenOdd(true); 
     threadEvenOdd th2 = new threadEvenOdd(false); 
     Thread t1 = new Thread(th1); 
     t1.setName("odd"); 
     Thread t2 = new Thread(th2); 
     t2.setName("even"); 
     //System.out.println(t1.getName() + " starts"); 
     t1.start(); 
     //System.out.println(t2.getName() + " starts"); 
     t2.start(); 
    } 
} 

Вот мои вопросы:

  1. Странная поток выполняет в функции printOdd(), в то время как даже поток выполняет в функции printEven(). Я использую один встроенный замок для обоих потоков; Я не понимаю, как два потока могут существовать в соответствующих синхронизированных блоках одновременно, потому что они используют одну и ту же блокировку.

  2. Я удалил сообщения связи потока (уведомлять, ждать) из моего кода, и все же я получил желаемый результат. Теперь мне интересно, действительно ли на моем коде вообще нужны потоковые сообщения.

  3. Я думаю, мне все же нужно работать над моим пониманием многопоточных понятий, поскольку я изо всех сил пытаюсь понять свой собственный код: p Может ли кто-нибудь объяснить, есть ли лучший способ сделать это, используя только многопотоковые концепции, которые у меня есть используемый?

ответ

1
  • Каждый поток имеет свой собственный путь выполнения с помощью кода. Даже если два потока запускают тот же самый код, они все еще имеют две различные точки выполнения через выполнение кода через код. Когда поток достигает синхронизированного оператора, он ожидает, что блокировка будет доступной - она ​​войдет в синхронизированный блок, только если ни один другой поток не находится внутри синхронизированного блока, защищенного одной и той же блокировкой.

  • Вы продолжаете получать тот же результат, хотя вы удалили уведомления/ожидания, могут быть случайными. Вы пробовали это с относительно большим значением поля count?

  • На данный момент трудно ответить на этот вопрос, так как вы не указали, какой результат вы ожидаете от этой программы. Является ли «1,3,5,7,9,2,4,6,8» допустимым результатом? Является ли "1,3,2,4,6,5,7,9,8"? Или «1,2,3,4,5,6,7,8,9» является единственным действующим выходом? Тем не менее, вот несколько быстрых точек:

  • Использование notifyAll() вместо уведомит

  • Минимизация состояние, которое между потоками. В этом случае вы делитесь обоими isOdd и c. Обратите внимание, что первое может быть вычислено из последнего через c % 2 == 1. Таким образом, вы можете иметь нечетность потоков, вместо того, чтобы поддерживать ее как часть общих данных.

  • Вместо совместного использования через статические поля создайте объект (с полями экземпляра) и передайте этот объект конструктору каждого потока. Затем вы можете использовать объект как блокировку.

Вот как это может выглядеть следующим образом:

class SharedData { 
    int c; 
    boolean isOdd; 
} 

class ThreadEvenOdd { 
    SharedData sharedData; 

    pubic ThreadEvenOdd(SharedData sd) { this.sharedData = sd } 

    ... 

    void printOdd(int count) { 
    try { 
     for(int i=0;i<count/2;i++) { 
     synchronized(sharedData) { 
      if(!sharedData.isOdd) { ... } 
      System.out.println(sharedData.c); 
      sharedData.c++; 
      sharedData.isOdd = false; 
      lock.notify(); 
      } 
     } 
     } 
    } 
    catch(Exception e) { 
     System.out.println(e); 
    } 
    } 

Хорошая вещь об этом является то, что вы можете начать определять реальные методы sharedData (например: метод, который увеличивает c и установить isOdd в соответствующее значение на основе значения c, что дополнительно упрощает код в классе потоков - и делает синхронизацию/уведомление менее чередующимися с обработкой данных, что делает код более читаемым и менее подверженным ошибкам.

+0

Спасибо за ответ Италия Маман. Мой выход предполагается {1,2,3,4,5,6,7,8, ....} Я попытался увеличить лимит счета и удалил потоковые межсоединения, он все же предоставил мне необходимые результаты – user2581707

+0

В ответ на ваши ответы вы указали несколько замечательных идей по внедрению блокировок и использованию полей экземпляра/статики. Я буду помнить об этом. Отличная работа благодаря мужчине! – user2581707