notify()和notifyAll()在我的java代码

时间:2016-08-19 12:28:46

标签: java multithreading wait synchronized notify

所以我一直在使用Java中的简单等待/通知示例,由于某种原因,我无法让它正常运行。如果有人能够看到可能是什么问题,我将非常感激!

class producer implements Runnable {
    StringBuffer sb;
    producer() {
        sb=new StringBuffer("");
    }

    public void run () {
        synchronized(sb) {
            for(int i = 0; i < 10; i++) {
                try { 
                    sb.append(i+" ");
                    System.out.println("Appending ... "); 
                } catch (Exception e) {}
            }
            sb.notify(); 
        }
    }
}

class consumer implements Runnable {
    producer p;
    consumer(producer pp) {
        this.p = pp;
    }

    public void run() {
        System.out.println("Rreached");
        synchronized(p.sb) { 
            try { 
                 p.sb.wait(); 
            } catch (Exception e) {}
            System.out.println(p.sb);
        }
    }
}

class Thread_Comunication {
    public static void main (String [] args) {
        producer p = new producer();
        consumer c = new consumer(p);

        Thread t1 = new Thread(p);
        Thread t2 = new Thread(c);
        t1.start();
        t2.start();
    }
}

输出:

Appending ...
Rreached   // randome Position
Appending ...
Appending ...
Appending ...
Appending ...
Appending ...
Appending ...
Appending ...
Appending ...
Appending ...  

所以由于某种原因,线程t1没有唤醒t2或者我完全错过了其他内容?

2 个答案:

答案 0 :(得分:3)

除非另一个线程在等待,否则Notify不会执行任何操作。您的代码完全取决于通知(需要条件变量的位置),并依赖于在生产者之前运行的消费者,以使其工作。

根据你的输出,生产者首先运行;它将在消费者有机会运行之前完整执行。 (对于消费者运行它需要获取生成器所持有的sb上的锁。)生产者调用notify但没有线程在等待,所以它没有效果。然后消费者等待并且没有通知,所以它无限期地挂起。

如果消费者首先运行,那么代码将正常终止。

避免编写依赖于一个线程发生在另一个线程之前的代码,因为您无法控制先执行的操作。当你等待时,你需要在一个测试条件的循环中进行。其中一个原因是,如果在线程开始等待之前设置了条件,则线程可以知道不要等待。

更改代码以使用条件:

import java.io.*;

class producer implements Runnable {
    StringBuffer sb;
    boolean done = false;
    producer() {
        sb=new StringBuffer("");
    }

    public void run () {

        synchronized(sb) {

            for(int i=0;i<10;i++) {
                try { 
                    sb.append(i+" ");
                    System.out.println("Appending ... "); 
                } catch (Exception e) {}
            }
            sb.notify(); 
            done = true;
        }


    }
}

class consumer implements Runnable {
    producer p;
    consumer(producer pp) {
        this.p=pp;
    }

    public void run() {
        System.out.println("Rreached");
        synchronized(p.sb) { 
            try { 
                while (!p.done) {
                 p.sb.wait(); 
                }
            } catch (Exception e) {}

            System.out.println(p.sb);
        }
    }
}


public class Communication {
    public static void main (String [] args) throws Exception {
        producer p= new producer();
        consumer c= new consumer(p);

        Thread t1= new Thread(p);
        Thread t2= new Thread(c);
        t2.start();
        t1.start();
    }
}

答案 1 :(得分:1)

  

所以我一直在使用Java中的简单等待/通知示例,由于某种原因,我无法让它正常运行。

您的代码存在的问题是notify()未被保留。如果producer首先进入synchronized阻止 ,那么consumer将无法输入它并转到wait,直到{{} 1}}退出循环并完成。由于所有producer次调用都发生在notify块的,所以当synchronized到达consumer时,{{1}已完成,不再调用wait()。这意味着producer已挂起。

即使您首先启动notify,您仍然会遇到可能导致consumer首先进入其consumer块的竞争条件 - 尤其如此,因为{ {1}}调用producer需要时间。虽然不是&#34;修复&#34;,如果您在synchronized来电之前使用consumer放慢System.out.println()的速度,您应该会看到它现在有效,因为{{1在 producer将其锁定之前,}}到达Thread.sleep(100)

有几种方法可以正确解决这个问题。通常我们使用wait / notify 另一个synchronized应检查的变量。在您的情况下,这可能是consumer变量本身,因为它受到保护。所以wait()可以做类似的事情:

producer