Java - многопоточность и синхронизация - PullRequest
0 голосов
/ 22 марта 2012

У меня есть две очень похожие программы, каждая из которых пытается запустить два потока OddThread и EvenThread и пытается печатать нечетные и четные числа в последовательности. Пока первый работает, второй зависает. Кто-нибудь может определить ошибку во второй программе?

Первый, который работает:

public class ThreadTest {

public static void main(String[] args) {
    System.out.println("Odd Even test");
    NumHolder objNumHolder = new NumHolder();
    Odd o1 = new Odd(objNumHolder, "Odd Number Thread");
    Even e1 = new Even(objNumHolder, "Even Number Thread");
    o1.start();
    e1.start();
}
}

class NumHolder {
private int intCurrNum;
private boolean isEven = false;

public synchronized void printOddNumber(String tname) {
    while (isEven == true){
        try {
            wait();
        }catch (InterruptedException e) {
        }
    }
    isEven = true;
    System.out.println("Thread Name="+tname + "===Number="+intCurrNum);
    intCurrNum += 1;
    notifyAll();
}

public synchronized void printEvenNumber(String tname) {
    while (isEven == false) {
        try {
            wait();
        } catch (InterruptedException e) {
        }
    }
    isEven = false;
    System.out.println("Thread Name="+tname + "===Number="+intCurrNum);
    intCurrNum += 1;
    notifyAll();
}
}

class Even extends Thread {
private NumHolder objNumHolder;

public Even(NumHolder p_objNumHolder, String name) {
    super(name);
    objNumHolder=p_objNumHolder;
}

public void run() {
    for (int i = 0; i < 10; i++) {
        objNumHolder.printEvenNumber(getName());
    }
}
}
class Odd extends Thread {
private NumHolder objNumHolder;

public Odd(NumHolder p_objNumHolder,String name) {
    super(name);
    objNumHolder = p_objNumHolder;
}

public void run() {
    for (int i = 0; i < 10; i++) {
        objNumHolder.printOddNumber(getName());
    }
}
}

Второй код, который висит:

class PrintClass {
int intCurrNum;
private boolean isEven = false;

synchronized void printOdd(){
    while(isEven){
        try{
            wait();
        }catch(InterruptedException ie){
            System.out.println("Interrupted exception in printOdd()");
            ie.printStackTrace();
        }
        isEven = true;
        System.out.println("Thread Name="+Thread.currentThread().getName() + "===Number="+intCurrNum);
        intCurrNum += 1;
        notifyAll();
    }
}

synchronized void printEven(){
    while(!isEven){
        try{
            wait();
        }catch(InterruptedException ie){
            System.out.println("Interrupted exception in printEven()");
            ie.printStackTrace();
        }
        isEven = false;
        System.out.println("Thread Name="+Thread.currentThread().getName() + "===Number="+intCurrNum);
        intCurrNum += 1;
        notifyAll();
    }
}
}
class ThreadOdd extends Thread {
PrintClass pc = null;

ThreadOdd(PrintClass pc , String name){
    super(name);
    this.pc = pc;
}

public void run(){
    for (int i = 0; i < 10; i++) {
        pc.printOdd();
    }
}
}
class ThreadEven extends Thread {
PrintClass pc = null;

ThreadEven(PrintClass pc,String name){
    super(name);
    this.pc = pc;
}

public void run(){
    for (int i = 0; i < 10; i++) {
        pc.printEven();
    }
}
}
public class EvenOddPrintClass {
public static void main(String[] args){
    PrintClass pc = new PrintClass();
    Thread to = new ThreadOdd(pc,"ThreadOdd");
    Thread te = new ThreadEven(pc,"ThreadEven");
    to.start();
    te.start();
}
}

Спасибо.

Ответы [ 4 ]

0 голосов
/ 30 марта 2012
public class CountDownApp
 {
 public static void main(String[] args)
 {
 Thread count1 = new CountDownEven();
 Thread count2 = new CountDownOdd();
 count1.start();
 count2.start();

 }
 }

 class CountDownEven extends Thread
 {
 public void run()
 {
 for(int i=10;i>0;i-=2)
 { 
 System.out.print(+i+"-");

 try {
    Thread.sleep(2);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
 }
 }

 }

 class CountDownOdd extends Thread 
 {
 public void run()
 {
 for(int i=9;i>0;i-=2)
 {
 System.out.print(+i+"-");

 try {
        Thread.sleep(2);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
 }
 }

 }
0 голосов
/ 22 марта 2012

В обеих версиях isEven начинается с false.

В первой версии printOddNumber пропустит весь цикл while, напечатает нечетное число, установит для isEven значение true и уведомит поток even, который будет печатать четное число, снова уведомит поток odd и т. Д. в последовательности.

Во второй версии printOddNumber пропустит весь цикл while, включая печать номера и уведомление о потоке even. После 10 попыток он выйдет, ничего не напечатав, и оставит нить even зависшей, даже не уведомив об этом.

0 голосов
/ 22 марта 2012

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

0 голосов
/ 22 марта 2012

Интересно. Итак, изначально isEven = false. Если printOdd() вызывается первым, то тест while (isEven) ложен, поэтому printOdd() немедленно выйдет из без генерации какого-либо вывода. Циклы while в вашей первой программе охватывают только тест wait, а не весь метод.

Затем, когда printEven() вызывается другим потоком, он будет вызывать wait() и зависать, так как нет другого потока для вызова notifyAll().

Вам следует только захотеть цикл while вокруг wait, поскольку вы собираетесь выйти после того, как вы все равно распечатаете четное или нечетное число, верно? Так что логика в первой программе правильная.

...