Java 中Object类的wait和notify方法的使用

wait和notify主要用在线程间的通信,
wait:让当前调用了wait的对象的所在线程堵塞,前提是当前线程获得了同步锁,不然会抛IllegalMonitorStateException异常
notify:通知调用了wait的对象继续执行,不堵塞,前提是调用了notify的对象已经出了synchronized代码块,释放了锁,才能通知成功
使用wait和notify要注意几点:

  1. wait和notify的调用者必须是同一个对象,只有这么才能通信
  2. wait和notify必须执行在synchronized代码块中,必须要加锁,不然会抛IllegalMonitorStateException异常
  3. wait和notify是每个对象都有的方法,是Object的方法,因为每个对象都有锁,锁是对象的基础,
  4. wait和notify必须用while循环,因为这个可以往复判断条件
  5. notify的执行必须跳出了synchronized,才能够通知到其他线程,就是要释放了自己的锁,才可以
    下面是一个生产者和消费的例子:
public class MainClass {


    static  int num=0;
    static  int maxCount=5;
    static int count=0;
    public  static void main(String args[])
    {

        final Object lock = new Object();




        new Thread(new Runnable() {
            @Override
            public void run() {
                String threadname=Thread.currentThread().getName();
                synchronized (lock)
                {
                    while(true)
                    {
                        while (count==maxCount)
                        {
                            try {
                                System.out.println(threadname+":"+"篮子里苹果满了,一共10个,需要等待被吃完了,才继续放");
                                lock.wait();

                            }
                            catch (InterruptedException e)
                            {

                            }


                        }
                        try {

                            Thread.sleep(500);
                            count++;
                            System.out.println(threadname+":"+"向篮子里添加了一个苹果,篮子里一共:"+count+"个苹果");
                            if(count==maxCount)
                            {
                                lock.notifyAll();
                            }

                        }
                        catch (InterruptedException e)
                        {

                        }
                    }
                }



            }
        },"product").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                String threadname=Thread.currentThread().getName();
                synchronized (lock)
                {
                    while(num<2)
                    {
                        while (count==0)
                        {
                            try {
                                System.out.println(threadname+":"+"篮子里苹果空了,需要等待放满了,才继续吃");

                                lock.wait();

                            }
                            catch (InterruptedException e)
                            {

                            }


                        }
                        try {

                            Thread.sleep(500);
                            count--;
                            System.out.println(threadname+":"+"吃了了一个苹果,篮子里还剩:"+count+"个苹果");
                            if(count==0)
                            {
                                num++;
                                System.out.println(threadname+":"+"一共要吃"+2+"篮子苹果,现在吃了"+num+"篮子苹果了");
                                if(num<2)
                                {
                                    lock.notify();
                                }

                            }


                        }
                        catch (InterruptedException e)
                        {

                        }
                    }
                    System.out.println(threadname+":"+"吃完5篮子苹果了,任务结束");
                }

            }
        },"customer").start();



    }
}

执行结果:

product:向篮子里添加了一个苹果,篮子里一共:1个苹果
product:向篮子里添加了一个苹果,篮子里一共:2个苹果
product:向篮子里添加了一个苹果,篮子里一共:3个苹果
product:向篮子里添加了一个苹果,篮子里一共:4个苹果
product:向篮子里添加了一个苹果,篮子里一共:5个苹果
product:篮子里苹果满了,一共10个,需要等待被吃完了,才继续放
customer:吃了了一个苹果,篮子里还剩:4个苹果
customer:吃了了一个苹果,篮子里还剩:3个苹果
customer:吃了了一个苹果,篮子里还剩:2个苹果
customer:吃了了一个苹果,篮子里还剩:1个苹果
customer:吃了了一个苹果,篮子里还剩:0个苹果
customer:一共要吃2篮子苹果,现在吃了1篮子苹果了
customer:篮子里苹果空了,需要等待放满了,才继续吃
product:向篮子里添加了一个苹果,篮子里一共:1个苹果
product:向篮子里添加了一个苹果,篮子里一共:2个苹果
product:向篮子里添加了一个苹果,篮子里一共:3个苹果
product:向篮子里添加了一个苹果,篮子里一共:4个苹果
product:向篮子里添加了一个苹果,篮子里一共:5个苹果
product:篮子里苹果满了,一共10个,需要等待被吃完了,才继续放
customer:吃了了一个苹果,篮子里还剩:4个苹果
customer:吃了了一个苹果,篮子里还剩:3个苹果
customer:吃了了一个苹果,篮子里还剩:2个苹果
customer:吃了了一个苹果,篮子里还剩:1个苹果
customer:吃了了一个苹果,篮子里还剩:0个苹果
customer:一共要吃2篮子苹果,现在吃了2篮子苹果了
customer:吃完5篮子苹果了,任务结束

这个就是两个线程通过wait和notify进行通知的例子,
我们知道notify的重载方法notifyAll,这个是通知所有的持有相同对象的线程,下面就是一个通知多线的例子:

public class WaitNotifyTest {

    // 在多线程间共享的对象上使用wait
    private String[] shareObj = {"true"};

    //线程等待
    class ThreadWait extends Thread{

        public ThreadWait(String name){
            super(name);
        }

        @Override
        public void run() {
            synchronized (shareObj){
                while ("true".equals(shareObj[0])){
                    System.out.println("线程"+this.getName()+"开始等待");
                    long startTime = System.currentTimeMillis();
                    try {
                        shareObj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    long endTime = System.currentTimeMillis();
                    System.out.println("线程"+this.getName()+"等待的时间为"+
                            (endTime - startTime));
                }
            }
            System.out.println("线程" + this.getName() + "等待结束");
        }
    }

    //线程唤醒
    class ThreadNotify extends Thread{

        public ThreadNotify(String name){
            super(name);
        }

        @Override
        public void run() {
            try {
                // 给等待线程等待时间
                sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (shareObj){
                System.out.println("线程" + this.getName() + "开始准备通知");
                shareObj[0] = "false";
                shareObj.notifyAll();
                System.out.println("线程" + this.getName() + "通知结束");
                try {
                    sleep(3000);
                }
                catch (InterruptedException e)
                {

                }

            }
            System.out.println("线程" + this.getName() + "运行结束");
        }
    }

    public static void main(String[] args) {
        WaitNotifyTest waitNotifyTest = new WaitNotifyTest();
        ThreadWait threadWait1 = waitNotifyTest.new ThreadWait("wait thread1");

        threadWait1.setPriority(2);
        ThreadWait threadWait2 = waitNotifyTest.new ThreadWait("wait thread2");
        threadWait2.setPriority(3);
        ThreadWait threadWait3 = waitNotifyTest.new ThreadWait("wait thread3");
        threadWait3.setPriority(4);

        ThreadNotify threadNotify = waitNotifyTest.new ThreadNotify("notify thread");

        threadNotify.start();
        threadWait1.start();
        threadWait2.start();
        threadWait3.start();
    }


}

结果:

线程wait thread1开始等待
线程wait thread3开始等待
线程wait thread2开始等待
//等待3秒
线程notify thread开始准备通知
线程notify thread通知结束
线程notify thread运行结束
//等待3秒
线程wait thread2等待的时间为6008
线程wait thread3等待的时间为6008
线程wait thread2等待结束
线程wait thread1等待的时间为6008
线程wait thread3等待结束
线程wait thread1等待结束

在上面的代码中有2点要注意:

  1. 给线程设置优先级setPriority,对notifyAll唤醒其他线程的先后顺序没有联系,先wait的先被唤醒
  shareObj.notifyAll();
                System.out.println("线程" + this.getName() + "通知结束");
                try {
                    sleep(3000);
                }

2、这里可以看出只有释放了自己的锁,才能唤醒其他线程,等待了3s,后其他线程才被唤醒,不是说调用了notify其他线程就会被唤醒,这要注意

Guess you like

Origin blog.csdn.net/fagawee/article/details/103274006