黑马程序员技术交流社区

标题: 等待唤醒机制 [打印本页]

作者: 王红霞    时间: 2012-7-17 10:21
标题: 等待唤醒机制
本帖最后由 王红霞 于 2012-7-17 11:41 编辑

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

class Input implements Runnable
{
        private Res r;
        Input(Res r)
        {
                this.r=r;
        }
        public void run()
        {
                int x=0;
                while(true)
                {
                        synchronized(r)
                        {
                                if(r.flag)
                                   wait();
                                if(x==0)
                                {
                                        r.name="mike";
                                        r.sex="man";
                                }
                                else
                                {
                                        r.name="lily";
                                        r.sex="girl";
                                }
                                x=(x+1)%2;
                                r.flag=true;
                                notify();//这样一定是表示要唤醒Output吗?如果是超过两个线程怎么识别是唤醒谁?如果是多个线程wait但是只想唤醒一个怎么解决?不在notify中加标记来说明是哪个线程被唤醒吗?
                        }
                }
        }
}

class Output implements Runnable
{
        private Res r;
        Output(Res r)
        {
                this.r=r;
        }
        public void run()
        {
                while(true)
                {
                        synchronized(r)//对象是不是可以是资源和类.class、this?还有什么吗?锁是任意对象,真的是其他的任意对象都可以吗?
                        {
                                if(!r.flag)
                                        wait();
                                System.out.println(r.name+"...."+r.sex);
                                r.flag=false;
                                notify();
                        }
                }
        }
}
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(out);
                t1.start();
                t2.start();
        }
}

作者: 王龙彪    时间: 2012-7-17 10:45
notify();//这样一定是表示要唤醒Output吗?如果是超过两个线程怎么识别是唤醒谁??不在notify中加标记来说明是哪个线程被唤醒吗?

因为你的Input类和Output用的都是同一个锁,即r
所以notify()会唤醒第一个线程池中在等待的线程.
这样如果有多个线程的话,会造成死锁,所以要使用notifyAll();这个函数.

synchronized(r)//对象是不是可以是资源和类.class、this?还有什么吗?锁是任意对象,真的是其他的任意对象都可以吗?

是的,非静态函数的锁可以是任意的对象.
静态锁就只能用本类的类对象,就是Class的对象.
作者: 王达    时间: 2012-7-17 10:55
class Res
{
        String name;
        String sex;
        boolean flag=false;
}

class Input implements Runnable
{
        private Res r;
        Input(Res r)
        {
                this.r=r;
        }
        public void run()
        {
                int x=0;
                while(true)
                {
                        synchronized(r)
                        {
                                if(r.flag)
                                   wait();
                                if(x==0)
                                {
                                        r.name="mike";
                                        r.sex="man";
                                }
                                else
                                {
                                        r.name="lily";
                                        r.sex="girl";
                                }
                                x=(x+1)%2;
                                r.flag=true;
                                notify();//这里一定是唤醒out,因为在f为false的情况下都会读一遍这里,此时只有out处于wait状态,所以只唤醒out。                        }
                }
        }
}

class Output implements Runnable
{
        private Res r;
        Output(Res r)
        {
                this.r=r;
        }
        public void run()
        {
                while(true)
                {
                        synchronized(r)//这里的对象是任意对象,只要是对象都可以,注意同一个同步内要用同一个对象                        {
                                if(!r.flag)
                                        wait();
                                System.out.println(r.name+"...."+r.sex);
                                r.flag=false;
                                notify();
                        }
                }
        }
}
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(out);
                t1.start();
                t2.start();
        }
}

这个notify是唤醒正在wait的线程,你现在只有两个线程如果你有过个线程的话,多个wait的话就不一定唤醒谁了,如果要唤醒多个线程可以用notifyAll,唤醒其他的,没有在notify中加标记这么一说。
作者: 黑马陈旭东    时间: 2012-7-17 11:22
   notify();//这样一定是表示要唤醒Output吗?如果是超过两个线程怎么识别是唤醒谁??不在notify中加标记来说明是哪个线程被唤醒吗?
          //这个唤醒功能唤醒的是等待池里排在第一位的的线程。谁是排第一的?就是最先等待的那条线程。)//对象是不是可以是资源和类.class、this?还有什么吗?锁是任意对象,真的是其他的任意对象都可以吗?
           //锁当然是任意对象都可以,不过前提是你的对象要先在成员位置上声明。你可以新创建一个Object对象来做锁。但一般为了简便,我们一般用本身对象this来做锁
作者: 党巾水    时间: 2012-7-17 11:37
这样一定是表示要唤醒Output吗?如果是超过两个线程怎么识别是唤醒谁??不在notify中加标记来说明是哪个线程被唤醒吗?

不一定。如果有至少2个线程在等待的话,它们会进入一个线程池,线程池里有先来后到的顺序的,唤醒是按照进入线程池的顺序来的。
当然,可以用notifyAll()这个方法来一次性唤醒所有线程。

对象是不是可以是资源和类.class、this?还有什么吗?锁是任意对象,真的是其他的任意对象都可以吗?

这里要区分是否为静态,
静态锁用字节码文件,就是XXX.class。
非静态可以是任意对象。

但是要记住同步的前提:
同步需要两个或者两个以上的线程。
多个线程使用的是同一个锁。
未满足这两个条件,不能称其为同步。
非静态虽说是任意对象,但是也要保证用的是统一对象。
作者: 王红霞    时间: 2012-7-17 11:42
刘馨琪 发表于 2012-7-17 11:37
这样一定是表示要唤醒Output吗?如果是超过两个线程怎么识别是唤醒谁??不在notify中加标记来说明是哪个线 ...

多提自己遇到的问题呀  
作者: 牛少锋    时间: 2012-7-17 11:44
  notify();//这样一定是表示要唤醒Output吗?如果是超过两个线程怎么识别是唤醒谁??不在notify中加标记来说明是哪个线程被唤醒吗?

这样的唤醒机制给人确实弄的是莫名其妙的的感觉很不舒服,如果是多生产者和多消费者的时候让人产生更多的郁闷。心里老感觉不舒服
我是硬着头皮把老毕的视频知识看完的,看到后面感觉还是新的1.5版本的特性好,好像就是专门解决这些问题而升级的新特性的新特性
下面我给你贴个老师讲的例子:也许新特性的唤醒机制 会让你感觉更合理点,直接唤醒指定的锁

/**
* JDK 1.5新特性;新特性 lock  java.util.concurrent.locks
* Lock 替换了原来的 synchronized对象;Condition 替换了原来的Object对象
* 实现了,本方只唤醒对方
* @author Administrator
*
*/

class Resource3{
        private String name;
        private int count=1;
        private boolean flag=false;
       
        //JDK 1.5新特性
        private Lock lock=new ReentrantLock();
        private Condition condition_pro=lock.newCondition();
        private Condition condition_con=lock.newCondition();
       
        public void set(String name){
                lock.lock();
                try{
                        while(flag){
                                try {
                                        condition_pro.await();
                                } catch (InterruptedException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                }
                        }
                        this.name=name+"  生产序号:"+count++;
                        System.out.println(Thread.currentThread().getName()+"  生产者..........."+this.name);
                        flag=true;
                        condition_con.signal();
                }finally{
                        lock.unlock();
                }
               
               
        }
        public void get(){
                lock.lock();
                try{
                        while(!flag){
                                try {
                                        condition_con.await();
                                } catch (InterruptedException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                }
                        }
                        System.out.println(Thread.currentThread().getName()+"   消费者........"+this.name);
                        flag=false;
                        condition_pro.signal();
                }finally{
                        lock.unlock();
                }
        }
}

class Procucer3 implements Runnable{
        private Resource3 r;
        public Procucer3(Resource3 r){
                this.r=r;
        }
        public void run() {
                while(true){
                        r.set("商品");
                }
        }
}

class Consumer3 implements Runnable{
        private Resource3 r;
        public Consumer3(Resource3 r){
                this.r=r;
        }
        public void run() {
                while(true){
                        r.get();
                }
        }
}




public class ThreadLianxi4 {

        /**
         * @param args
         */
        public static void main(String[] args) {
                Resource3 r=new Resource3();
                Procucer3 p=new Procucer3(r);
                Consumer3 c=new Consumer3(r);
                Procucer3 p2=new Procucer3(r);
                Consumer3 c2=new Consumer3(r);
               
                Thread t=new Thread(p);
                Thread t2=new Thread(c);
                Thread t3=new Thread(p2);
                Thread t4=new Thread(c2);
                t.start();
                t2.start();
                t3.start();
                t4.start();

        }

}






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