A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© ぺsimon☆ 中级黑马   /  2013-5-17 00:51  /  4253 人查看  /  10 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 ぺsimon☆ 于 2013-5-17 13:54 编辑

/*
生产者和消费者的升级版


问题:t1进来判断flag=false,输入数据,然后把flag置为true ,然后出了同步函数,假设这时候是t2抢到了cpu执行权,运行run方法中的代码
        发现false为true,读了wait()方法

        那么这时我就不懂了,t2在同步函数里等着了,虽然释放了执行权,但是它是在同步函数里的,老师说同步函数中只能有一个线程存在,t2还没执行完同步函数
        那么这时候t1,t3和t4就进不去了啊,我的理解是这样,希望兄弟们说个明白

       还有如果t2读到的是sleep方法,又会怎样呢?
*/

class Res
{
        private String name;
        private String sex;
        private boolean flag=false;

        public synchronized void setRes(String name,String sex)
        {
                //当flag为true时生产者就等待,否则就生产
                //这里等待线程醒来之后要判断flag的值,以免造成安全隐患
                while(flag)
                   try{this.wait();}catch(Exception e){}
               
                this.name=name;
                this.sex=sex;
                System.out.println(Thread.currentThread().getName()+"生产者"+name+"..."+sex);

                flag=true;
                //这里用notifyAll唤醒所有线程,避免唤醒的是本方线程,注意如果用notify,它唤醒的是进入线程                池中的第一个线程,有可能唤醒的是本方线程,造成所有的线程都在等待

                this.notifyAll();
        }

        public synchronized void getRes()
        {

                //当flag为false时消费者就等待,否则就消费
                while(!flag)
                  try{this.wait();}catch(Exception e){}

                System.out.println(Thread.currentThread().getName()+"消费者"+name+"-----"+sex);
                flag=false;
                this.notifyAll();
        }
}

class Input implements Runnable
{

        private Res r;
        Input(Res r)
        {
                this.r=r;
        }

        public void run()
        {
                int x=0;
                while(true)
                {
                        if(x==0)
                        {
                                r.setRes("mike","man");
                        }

                        r.setRes("丽丽","女");
                        x=(x+1)%2;
                }
        }        
}

class Output implements Runnable
{
        private Res r;
        Output(Res r)
        {
                this.r=r;
        }

        public void run()
        {
                while(true)
                r.getRes();
        }
}

class InputOutputDemo
{
        public static void main(String[] args)
        {
                Res r=new Res();
                Input in=new Input(r);
                Output out=new Output(r);

                Thread t1=new Thread(in);
                Thread t2=new Thread(in);

                Thread t3=new Thread(out);
                Thread t4=new Thread(out);

                t1.start();
                t2.start();
                t3.start();
                t4.start();
        }
}

评分

参与人数 1技术分 +1 收起 理由
Sword + 1

查看全部评分

10 个回复

倒序浏览
t1和t2所属是同一个对象,t3和t4是所属另一个对象  ,t1和t2用的同步函数是setRes, t3和t4调用的是getRes
过程是这样的: t1进来判断flag=false,输入数据,然后把flag置为true ,然后出了同步函数,假设这时候是t2抢到了cpu执行权,运行run方法中的代码
        发现false为true,读了wait()方法,可是t3和t4用的是getRes,t3如果拿到执行权会去getRes里面执行,然后会把标记flag改为false
回复 使用道具 举报
  同步函数中只能有一个线程存在,这句话理解错误,或是说老师解释的不清楚也行。更精确的说应该是,同步限定代码块中同一时间内只能有一个执行线程的存在。
  线程同步是为了解决什么问题你知道吗?
  
  程序执行都是一行一行向下执行的。遇到函数就跳转到函数头开始执行(内联函数是直接将函数体复制到调用处)就算你的类设计的再复杂,代码依然是一行一行执行的。
  多线程就是说有可能在执行完一行后,突然跑去执行不相关的另外一行了。这时有可能上一行的操作并没有完成(对一个变量)下一行就又对这个变量操作了。就会造成数据错乱。
  另外还有一种情况,比如你要用写一个程序启动你电脑上的N多个进程,每启用一个进程用一个线程去调用这个进程,但是同一时间启动的话会可能死机,这时候你就须要同步一下执行的过程,让开启进程的函数只能同一时间被一个线程调用,启动完一个再让另一个线程调用去启动别的。免的同一时间N多个进程同时启动死机。
  举例说,你玩过游戏吧,有的游戏可以同时开N多个窗口,你如果用鼠标一阵狂双击,是不是会启动好多个,启动这么快有时候会死机的。所以一般你须要双击完一个稍等一下再双击下一个。做到程序里就是把你鼠标双击的操作封装进一个函数,这个函数同一时间只能有一个线程调用。

  明白了这个再看同步,wait是说当前线程停在这里,wait是程序员自己写上去的,既然程序员写了这句,他就应该知道线程停在这里不会出现数据错乱,停在这里就代表着它放弃了执行权,就跟他出了同步函数是一样的。
  举例来说,一个领导指挥两个人挖水沟。但是水沟太窄了,只能下去一个人,领导一合计,那甲挖一会,乙休息一会,完了换乙来挖,甲休息。领导说synchronized甲就跳进水沟挖去了,另一个人就跳不进去了吧?过了一会,领导又说wait。甲就爬出来去休息去了,这时沟里没人了乙就能进去了。

  sleep和wait是一样的,只是sleep有时间指定,这就好像是说那领导发话了,甲你去休息3分钟,3分钟后过来继续干活,过了3分钟甲回来干活了,如果发现沟里没人他就直接下去了,如果发现乙还在沟里继续干活呢,他就只能先在沟边上等着
回复 使用道具 举报
本帖最后由 黑马-许鹏 于 2013-5-17 03:00 编辑

其实一句话就可以解释清楚,线程在调用wait方法之前,会释放掉所占有的“锁标志”。这一点毕老师没有讲,我也遇到了困惑,后来查了资料才知道的。
回复 使用道具 举报
你好,请参考下面这两句话理解程序

wait() 和 sleep() 的区别:
1,wait() 执行后,释放执行权,也释放锁,与它同步的线程或者其它的线程都可以拿到执行权。
2,sleep() 执行后,释放执行权,但不释放锁,即与它不拥有同一个锁的线程可以拿到执行权,但与它同步的线程不可以拿到执行权。

回复 使用道具 举报

看看我的总结,不懂再问我。
1.核心区别:sleep用于线程控制,wait用于线程间的通信。
sleep是Thread类的方法,是让线程休息一段时间,然后自动恢复运行,与其他线程无关,与同步无关,也与锁无关(拿锁时不会释放锁)。
wait是Object类的方法,也就是锁的方法,必然在同步中,根据java7.0的解释(The thread releases ownership of this monitor and waits),wait就是让当前线程释放锁并等待。(java 1.6中文版API翻译是错误的,“该线程发布对此监视器的所有权并等待”,release应该翻译成释放)。
public static void sleep(long millis)
                  throws InterruptedException
Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers. The thread does not lose ownership of any monitors.
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。该线程不丢失任何监视器的所属权。
public final void wait()
                throws InterruptedException
Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。
当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。

2.唤醒和中断
sleep一觉睡到自然醒,wait就必须其他拿锁的线程调用notify(唤醒一个)或notifyAll(全部唤醒)方法来唤醒。wait的线程被唤醒后,不会立即执行,它要和其他具备执行资格的线程正常的争抢执行权。
由于sleep和wait会使线程处于阻塞或冻结状态,可能等不到所等的事件而无法终止,所以需要从外部调用interrupt()方法中断他们的阻塞状态,此时就会抛InterruptedException异常(API对这个异常的描述为:当线程在活动之前或活动期间处于正在等待、休眠或占用状态且该线程被中断时,抛出该异常。关于如何处理InterruptedException异常,参见资料http://www.ibm.com/developerworks/cn/java/j-jtp05236.html。)
参考资料:java多线程 sleep()和wait()的区别
http://www.cnblogs.com/octobershiner/archive/2011/10/28/2227705.html
回复 使用道具 举报
黑马-许鹏 发表于 2013-5-17 02:59
其实一句话就可以解释清楚,线程在调用wait方法之前,会释放掉所占有的“锁标志”。这一点毕老师没有讲,我 ...

哦,原来是这样,明白了谢谢
回复 使用道具 举报
逸盏清茶 发表于 2013-5-17 01:26
t1和t2所属是同一个对象,t3和t4是所属另一个对象  ,t1和t2用的同步函数是setRes, t3和t4调用的是getRes
...

虽然t1和t2用的同步函数是setRes,t3和t4用的是getRes
但是这四个线程不是用的是同一个锁吗,哥们?这4个线程,在锁里只能有一个线程在运行,是吗
回复 使用道具 举报
slatop@qq.com 发表于 2013-5-17 01:49
  同步函数中只能有一个线程存在,这句话理解错误,或是说老师解释的不清楚也行。更精确的说应该是,同步 ...

 sleep不是不释放锁的吗,哥们
回复 使用道具 举报
石贤芝 发表于 2013-5-17 05:02
你好,请参考下面这两句话理解程序

wait() 和 sleep() 的区别:

哦,原来是这样谢谢
回复 使用道具 举报
librazeng 发表于 2013-5-17 10:11
看看我的总结,不懂再问我。
1.核心区别:sleep用于线程控制,wait用于线程间的通信。
sleep是Thread类的 ...

哦,好的谢谢
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马