Java 难以理解线程间通信

Java 难以理解线程间通信,java,multithreading,wait,notify,Java,Multithreading,Wait,Notify,有人能解释一下线程间通信的程序吗 //生产者和消费者的正确实施 class Q { int n; boolean valueSet = false; synchronized int get() { while(!valueSet) try { wait(); } catch(InterruptedException e) { System.ou

有人能解释一下线程间通信的程序吗

//生产者和消费者的正确实施

class Q {
    int n;
    boolean valueSet = false;
    synchronized int get() {
        while(!valueSet)
            try {
                wait();
            } catch(InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        System.out.println("Got: " + n);
        valueSet = false;
        notify();
        return n;
    }
    synchronized void put(int n) {
        while(valueSet)
            try {
                wait();
            } catch(InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        this.n = n;
        valueSet = true;
        System.out.println("Put: " + n);
        notify();
    }
}

class Producer implements Runnable {
    Q q;

    Producer(Q q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }
    public void run() {
        int i = 0;
        while(true) {
            q.put(i++);
        }
    }
}

class Consumer implements Runnable {
    Q q;
    Consumer(Q q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }
    public void run() {
        while(true) {
            q.get();
        }
    }
}

class PCFixed {
    public static void main(String args[]) {
        Q q = new Q();
        new Producer(q);
        new Consumer(q);
        System.out.println("Press Control-C to stop.");
    }
}
输出

Put:1 得到:1 Put:2 得到:2 Put:3 得到:3 Put:4 得到:4


就我而言,这非常令人困惑,尤其是使用notify()和wait()的put和get方法。还请解释为什么使用布尔值

所以有两个线程。Qne正在设置此Q数据结构上的值,另一个正在读取这些值。Q使用一个布尔标志来判断是否存在新值,一旦读取现有值,该标志就会被清除

get使用等待阻塞,直到有新值可读取。读取新值后,它会将标志设置回false

put等待,直到另一个队列读取了新值,然后再将其设置为新值,然后通过设置布尔标志并调用notify让另一个线程知道

请记住,wait会放弃锁,以便其他线程可以获取它

需要使用布尔标志,因为线程可能会在未收到通知的情况下停止等待。线程被唤醒并不意味着它收到了通知。此外,即使线程得到通知,因为线程在开始等待时放弃了锁,所以当前的状态是未知的(一般来说,在多线程程序中,另一个线程可能会在通知线程到它可以重新获得锁的时间之间潜入并阻塞某些内容)因此,线程一旦拥有锁,就必须重新测试条件


像wait和notify这样的结构是大型并发程序的构建块,因此在一个只有两个线程的小示例中,有些事情可能没有那么有意义

基本上看,这是一种使用同步方法的多线程通信

这里的简单要求是

1) 首先允许为制作人编写

2) 下一步允许为消费者阅读

class Q {
    int n;
    boolean valueSet = false;
    synchronized int get() {
        while(!valueSet)
            try {
                wait();
            } catch(InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        System.out.println("Got: " + n);
        valueSet = false;
        notify();
        return n;
    }
    synchronized void put(int n) {
        while(valueSet)
            try {
                wait();
            } catch(InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        this.n = n;
        valueSet = true;
        System.out.println("Put: " + n);
        notify();
    }
}

class Producer implements Runnable {
    Q q;

    Producer(Q q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }
    public void run() {
        int i = 0;
        while(true) {
            q.put(i++);
        }
    }
}

class Consumer implements Runnable {
    Q q;
    Consumer(Q q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }
    public void run() {
        while(true) {
            q.get();
        }
    }
}

class PCFixed {
    public static void main(String args[]) {
        Q q = new Q();
        new Producer(q);
        new Consumer(q);
        System.out.println("Press Control-C to stop.");
    }
}
使用布尔标志
valueSet
控制的

对于生产者意味着Q的put方法,逻辑是这样工作的 如果
valueSet
true
意味着已经完成了写入操作,则要求名为thread的put方法等待。所以要等到有人打电话通知

当然,它不会继续进一步的逻辑,并继续等待有人打电话通知

来到读者面前意味着得到Q

如果
valueSet
false
表示writer正在执行,则要求名为thread的get方法等待。所以要等到有人打电话通知


因此,一旦编写器完成了执行,它会在最后调用notify,现在阅读器线程醒来并开始阅读。

@NathanHughes我很抱歉,作为一个noob真的很尴尬,但你能帮我一下吗?我的编程技能真的很差。我只是说,最好把你不懂的东西说清楚。否则我们不知道该解决什么问题。无法理解y我的问题被否决了。在stackoverflow中提出疑问是罪过吗。我想如果我再问一两个问题,我甚至不会有声誉评论或投票支持答案…grrrThank..现在在你的问题上->valueSet变量默认初始化为false,因为while(valueSet)inside-put方法必须失败,以使生产者线程最初不会等待,因为首先我们应该允许生产者生成数据,而不是让它等待。一旦编写完put方法end,我们将valueSet设置为true,然后调用notify(),如果您仔细观察的话,这会使读者醒来并使用valueSet true值,这会导致它绕过while,因为(!valeSet)并允许阅读..像这样继续..有疑问吗?因为生产者和消费者不应该有订单依赖关系,你不想要求必须先调用其中一个。但应该有订单,对吗!!我的意思是,如果生产商不把任何东西放进队列,消费者可以得到什么,那么不应该先给生产商打电话……Q不应该坚持订单。否则,你将有一个竞赛条件,如果错误的线程首先到达那里,它将被打破。实际上,如果消费者首先到达那里,它就会放弃锁并等待通知。它说,当两个线程在同一时间调用同一个方法时,会发生争用情况,但在这里,两个线程在同一时间访问两个不同的方法。此外,回答我问题的另一个人(在评论部分)说,应该有一个顺序。那么,你能澄清一下困惑吗?你的定义太狭隘了,请看。jvm规范不保证哪个线程将启动并由调度程序选择首先执行。