黑马程序员技术交流社区

标题: 求好心人回答,问题在标注的地方(关于消费者和生产者) [打印本页]

作者: 潜伏    时间: 2014-1-11 13:37
标题: 求好心人回答,问题在标注的地方(关于消费者和生产者)
package thread.conAndpro;

public class Synchronized_Test {
        public static void main(String[] args) {
                Resouse_1 r=new Resouse_1();
                Producer_1 p=new Producer_1(r);
                Consumer_1 c=new Consumer_1(r);
               
                new Thread(p).start();
                new Thread(p).start();
                new Thread(c).start();
                new Thread(c).start();
        }
}

class Resouse_1{
        private int count;
        Boolean flag=false;
       
        public synchronized void produce(String name){
                while(flag)
                        try {
                                this.wait();;
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                System.out.println(name+"生产了"+(++count));
                flag=!flag;
//我想问这地方如果消费者的两个线程都在wait()的话,生产者的一个线程将所有的线程都唤醒,是不是会造成
//消费者的两个线程都在运行,消费者的两个线程都判断标记为false,所以都往下执行,不就导致共享数据错误??、
                this.notifyAll();
        }
       
        public synchronized void consume(String name){
                while(!flag)
                        try {
                                this.wait();
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                System.out.println(name+"消费了。。。。。。"+count);
                flag=!flag;
                this.notifyAll();
        }
}

class Producer_1 implements Runnable{
        private Resouse_1 r;
       
        Producer_1(Resouse_1 r){
                this.r=r;
        }
       
        public void run(){
                while(true)
                        r.produce(Thread.currentThread().getName());
        }
}

class Consumer_1 implements Runnable{
        private Resouse_1 r;
       
        Consumer_1(Resouse_1 r){
                this.r=r;
        }
       
        public void run(){
                while(true)
                        r.consume(Thread.currentThread().getName());
        }
}

作者: ixiangfeng    时间: 2014-1-11 15:26
你说的情况是if来判断flag才会发生的 但是你这里用while来判断的话就不会出现,一旦线程被唤醒后就会继续进到while里面来判断
作者: 潜伏    时间: 2014-1-12 00:54
ixiangfeng 发表于 2014-1-11 15:26
你说的情况是if来判断flag才会发生的 但是你这里用while来判断的话就不会出现,一旦线程被唤醒后就会继续进 ...

我知道是while啊,我说的就死while。你看我问的:我想问这地方如果消费者的两个线程都在wait()的话,生产者的一个线程将所有的线程都唤醒,是不是会造成消费者的两个线程都在运行,消费者的两个线程都判断标记为false,所以都不会冻结,都往下执行,不就导致共享数据错误??、
作者: 75100313    时间: 2014-1-12 08:30
synchronized 你这个关键字是用来干啥的? 怎么能两个消费者同时执行呢
明显是一个进去执行完方法里面所有的代码 另外一个消费者才进来判断啊
作者: ixiangfeng    时间: 2014-1-12 12:17
潜伏 发表于 2014-1-12 00:54
我知道是while啊,我说的就死while。你看我问的:我想问这地方如果消费者的两个线程都在wait()的话,生 ...

CPU不可能同时运行两个线程的,两个消费者的线程都被唤醒了就是说他们两个线程都有执行资格,但不一定有执行权,而假设两个消费者中的一个抢到CPU执行权的话,那它就会去判断一下flag,这时不符合wait的条件,它就执行下面的代码,会改变flag,这时即使另外一个线程抢到执行权也会到while里面判断flag,而不是直接执行下面的代码
作者: 孤独的天奇    时间: 2014-1-12 12:56
双核cpu是可以同时运行两个线程的
作者: 潜伏    时间: 2014-1-13 00:27
75100313 发表于 2014-1-12 08:30
synchronized 你这个关键字是用来干啥的? 怎么能两个消费者同时执行呢
明显是一个进去执行完方法里面所有 ...

不是的,当一个消费线程拿到锁后,如果通过判断语句满足的话就会wait,同时也会释放锁,消费的另一线程也可能拿到锁,进而通过判断语句又wait了,锁释放,此时生产线程拿到锁,就执行生产语句。是不是???、呵呵呵
作者: 潜伏    时间: 2014-1-13 00:31
ixiangfeng 发表于 2014-1-12 12:17
CPU不可能同时运行两个线程的,两个消费者的线程都被唤醒了就是说他们两个线程都有执行资格,但不一定有 ...

当然连个消费者都会判断标记,不过如果一个消费线程判断满足后,执行while后面的代码,而没有执行到打印代码或者改变标记的代码就放弃了执行权,另外一线程恰好获得执行权,判断标记也满足不就业往下执行吗???????????????????????????????????????
作者: ixiangfeng    时间: 2014-1-13 11:28
潜伏 发表于 2014-1-13 00:31
当然连个消费者都会判断标记,不过如果一个消费线程判断满足后,执行while后面的代码,而没有执行到打印 ...

你忘了synchronized了吗 一个线程在执行代码时另外一个线程即使获取到了CPU的执行权也是进不去的 像你说的如果一个线程进去了,然后不符合while的条件,那它就执行while下面的代码,而即使它还没有执行到打印或者改变标记的代码时就放弃了执行权,另外一线程获得了执行权也是进不去的,因为被synchronized锁住了,还有不知道你是不是对wait不太清楚,再给你说一下,synchronized是同步,锁上了就不能有两条线程在里面执行代码,而wait方法是会释放锁的,也就是说假如有一线程进去了synchronized方法里面然后遇到了wait方法,那这线程就会释放锁,相当于里面没有线程在执行,另外一个线程才可以进去
作者: ixiangfeng    时间: 2014-1-13 11:30
75100313 发表于 2014-1-12 08:30
synchronized 你这个关键字是用来干啥的? 怎么能两个消费者同时执行呢
明显是一个进去执行完方法里面所有 ...

wait方法会释放锁的,而这里synchronized方法里面也没有同时两个线程在执行,因为一个线程进去遇到wait方法后就会等待,然后释放锁,这时相当于里面没有线程,另外一个线程是可以进去的
作者: 75100313    时间: 2014-1-14 08:28
本帖最后由 75100313 于 2014-1-14 08:56 编辑
ixiangfeng 发表于 2014-1-13 11:30
wait方法会释放锁的,而这里synchronized方法里面也没有同时两个线程在执行,因为一个线程进去遇到wait方 ...
关键就是那个while()!

作者: ixiangfeng    时间: 2014-1-14 10:09
75100313 发表于 2014-1-14 08:28
关键就是那个while()!

线程进去同步函数里面 如果等待了 然后被唤醒了,它就会重新判断while循环的条件,你看一下我上面的解释
作者: 75100313    时间: 2014-1-14 10:45
ixiangfeng 发表于 2014-1-14 10:09
线程进去同步函数里面 如果等待了 然后被唤醒了,它就会重新判断while循环的条件,你看一下我上面的解释 ...

老大 我有点晕了  那为什么前面要加synchronized 这个啊 不是释放锁?
还不如不加这个  我晕了  这个问题我都觉得很白痴  求解答啊
作者: ixiangfeng    时间: 2014-1-14 11:13
75100313 发表于 2014-1-14 10:45
老大 我有点晕了  那为什么前面要加synchronized 这个啊 不是释放锁?
还不如不加这个  我晕了  这个问题 ...

加了synchronized在这个函数上是同步函数,简单地说同步函数的作用是加锁,使得两条线程同时执行函数里面的代码这种情况不会发生,不是释放锁,建议你还是回去看一下毕老师12天1-5的视频
作者: 75100313    时间: 2014-1-14 11:19
ixiangfeng 发表于 2014-1-14 11:13
加了synchronized在这个函数上是同步函数,简单地说同步函数的作用是加锁,使得两条线程同时执行函数里面 ...

两个线程 都wait() 等待,都在synchronized形容的函数的方法体内  现在不是就相当于都在执行了?
作者: ixiangfeng    时间: 2014-1-14 11:28
75100313 发表于 2014-1-14 11:19
两个线程 都wait() 等待,都在synchronized形容的函数的方法体内  现在不是就相当于都在执行了?  ...

synchronized实现多个线程不能同时操作里面的代码是用监视器或者说是锁,一个线程进去了就会把锁给锁上,其它的线程就进不去了,而wait方法有一个功能就是把锁给打开,synchronized里面的线程一遇到wait方法就会把锁给打开同时在原地呆着,这时因为锁开了所以其它线程可以进去,线程在里面wait是不可能执行代码的,所以两个或者多个线程在里面wait的话并不是说多条线程在里面执行代码
作者: 75100313    时间: 2014-1-14 11:36
ixiangfeng 发表于 2014-1-14 11:28
synchronized实现多个线程不能同时操作里面的代码是用监视器或者说是锁,一个线程进去了就会把锁给锁上, ...

假如说生产者 1号和2号 两条线程  都在执行了wait()方法后  在等待 。 对面消费者一看 没有物品了  那么直接
notifyAll() 把1号和2号都换醒了  1号进程一判断标记是true 马上要生产的时候 ,2号线程 执行 ,也来判断标记。 也是ture。。。结果一下生产了2个。。。会不会这样啊   换句话说 2个线程被唤醒之后 是如何保证 同步的?
作者: 汪洋大海    时间: 2014-1-14 13:05
这个题目如果用blockingqueue来做的话应该简单的多。
作者: ixiangfeng    时间: 2014-1-14 17:23
75100313 发表于 2014-1-14 11:36
假如说生产者 1号和2号 两条线程  都在执行了wait()方法后  在等待 。 对面消费者一看 没有物品了  那么 ...

一个synchronized只有一个锁,像你说的1号和2号被唤醒后,两个都具有执行资格,但是最多只能有一个具有执行权,假如1号线程抢到CPU的执行权,即使1号线程执行到里面一半代码时失去了CPU的执行资格,这时2号线程也不可能执行里面的代码,因为锁还是在1号线程那里,相当于它要动就要拿到锁才动得了
作者: 75100313    时间: 2014-1-14 20:35
ixiangfeng 发表于 2014-1-14 17:23
一个synchronized只有一个锁,像你说的1号和2号被唤醒后,两个都具有执行资格,但是最多只能有一个具有执 ...

十分感谢  谢谢 真心感谢!
作者: 孤独的天奇    时间: 2014-1-14 21:44
调用notify,不是说消费者线程马上就运行,而是这两个消费者线程都有了运行的资格,谁先抢到cpu谁就运行。
作者: 潜伏    时间: 2014-1-14 22:52
ixiangfeng 发表于 2014-1-14 17:23
一个synchronized只有一个锁,像你说的1号和2号被唤醒后,两个都具有执行资格,但是最多只能有一个具有执 ...

你解释的确实很好,看来你是高手中的高手,理解的都很透彻。膜拜高手!!!可否留下个联系方式?
作者: 潜伏    时间: 2014-1-14 23:01
ixiangfeng 发表于 2014-1-14 17:23
一个synchronized只有一个锁,像你说的1号和2号被唤醒后,两个都具有执行资格,但是最多只能有一个具有执 ...

你想表达的是只能有一线程拿到锁。而老毕讲的锁,打了个上火车卫生间的例子。就是说门上显示有人,别的人就不能进来。并且老毕讲的是判断锁,我以前的理解是1号和2号被唤醒后都不用再判断锁,所以都可以执行代码,就相当于两个人同时被锁在卫生间,都可以在里面活动。    听了你的讲解:好像是即使唤醒后还要判断死否拿到锁,就相当于谁拿有钥匙才能执行(如果卫生间有钥匙的话),是不是可以这样理解???????
作者: ixiangfeng    时间: 2014-1-14 23:11
潜伏 发表于 2014-1-14 23:01
你想表达的是只能有一线程拿到锁。而老毕讲的锁,打了个上火车卫生间的例子。就是说门上显示有人,别的人 ...

我是这样理解的,老毕说的火车卫生间的例子应该也可以,不过执行了wait之后就相当于出去了,这时别人也可以进去了 理解得差不多就好 有时太深究会很痛苦的,再理解深一些例如多核CPU会怎样等问题,要完完全全理解的话估计还要学很多相关的东西
作者: ixiangfeng    时间: 2014-1-14 23:12
本帖最后由 ixiangfeng 于 2014-8-5 21:28 编辑

                                                                                                                         ·                                                                              






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2