wait()和sleep() notify()/notifyAll()区别

wait():释放占有的对象锁,线程进入等待池,释放cpu,而其他正在等待的线程即可抢占此锁,获得锁的线程即可运行程序。

wait函数必须在同步代码块中调用(也就是当前线程必须持有对象的锁),他的功能是这样的:

我累了,休息一会儿,对象的锁你们拿去用吧,CPU也给你们。

调用了wait函数的线程会一直等待,直到有其他线程调用了同一个对象的notify或者notifyAll方法才能被唤醒,需要注意的是:被唤醒并不代表立即获得对象的锁。也就是说,一个线程调用了对象的wait方法后,他需要等待两件事情的发生:

  1. 有其他线程调用同一个对象的notify或者notifyAll方法
  2. 被唤醒之后重新获得对象的锁

而sleep()不同的是,线程调用此方法后,会休眠一段时间,休眠期间,会暂时释放cpu,但并不释放对象锁。也就是说,在休眠

期间,其他线程依然无法进入此代码内部。休眠结束,线程重新获得cpu,执行代码。

wait()和sleep()最大的不同在于:wait()会释放对象锁,而sleep()不会!

notify()/notifyAll()区别:

notify(): 该方法会唤醒因为调用对象的wait()而等待的线程,其实就是对对象锁的唤醒,从而使得wait()的线程可以有机会获取对象锁(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还 在别人手里,别人还没释放)。调用notify()后,并不会立即释放锁,而是继续执行当前代码,直到synchronized中的代码全部执行完毕,才会释放对象锁。释放对象锁后,紧接着JVM则会在等待的线程中调度一个线程去获得对象锁,执行代码。需要注意的是,wait()和notify()必须在synchronized代码块中调用

notifyAll()则是唤醒所有等待的线程。

为了说明这一点,举例如下:

两个线程依次打印"A""B",总共打印10次:



public class Test {

    public static final Object obj = new Object();

    public static void main(String[] args) {

        new Thread( new Produce()).start();
        new Thread( new Consumer()).start();

    }
}

public class Produce implements Runnable {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        int count = 10;
        while (count > 0) {
            //用Test类中的public static final Object obj = new Object();对象作为锁,        
            //目的是:使得线程A 线程B公用一把锁
            synchronized (Test.obj) {

                //System.out.print("count = " + count);
                System.out.println("A");
                count--;
                /**
                 notify( )方法只会通知等待队列中的第一个相关线程(例子中只有2个线程 实际开发中 可能有多个线程)
                (不会通知优先级比较高的线程),当调用Test. obj.notify后,Produce 调用线程依旧持有obj锁,
                 因此,Consumer 线程虽被唤醒,但是Consumer 仍无法获得obj锁。直到Produce 调用线程退出synchronized块,
                 释放obj锁后,Consumer 线程才获得锁继续执行。
                 */
                Test.obj.notify();

                try {
                    /**
                     释放占有的对象锁,调用了wait函数的线程会一直等待,直到有其他线程(Consumer 线程)
                     调用了同一个对象(Test. obj)的notify方法才能被唤醒
                     */
                    Test.obj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}

public class Consumer implements Runnable {

    @Override
    public synchronized void run() {
        // TODO Auto-generated method stub
        int count = 10;
        while(count > 0) {
            //用Test类中的public static final Object obj = new Object();对象作为锁
            //目的是:使得线程A 线程B公用一把锁
            synchronized (Test. obj) {

                System. out.println( "B");
                count --;
                /**
                 notify( )方法只会通知等待队列中的第一个相关线程(例子中只有2个线程 实际开发中 可能有多个线程)
                (不会通知优先级比较高的线程),当调用Test. obj.notify后,Consumer调用线程依旧持有obj锁,
                 因此,Produce 线程虽被唤醒,但是Produce 仍无法获得obj锁。直到Consumer 调用线程退出synchronized块,
                 释放obj锁后,Produce 线程才获得锁继续执行。
                 */
                Test. obj.notify();

                try {
                    /**
                     释放占有的对象锁,调用了wait函数的线程会一直等待,
                     直到有其他线程(Produce线程)调用了同一个对象(Test. obj)的notify方法才能被唤醒
                     */
                    Test. obj.wait();

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}

打印结果:

A
B
A
B
A
B
A
B
A
B
A
B
A
B
A
B
A
B
A
B

 

通过上述步骤,相信大家已经明白这两个方法的使用了,但该程序还存在一个问题,当while循环不满足条件时,肯定会有线程还在等待资源,所以主线程一直不会终止。当然这个程序的目的仅仅为了给大家演示这两个方法怎么用。

由于synchronized圈的代码块 执行完成 就会释放对象锁 所以 可以改成这样 主线程就会停止了:

package org.luzhen.test;

public class Test1 {

    public static final Object obj = new Object();

    public static void main(String[] args) {

        new Thread( new Produce()).start();
        new Thread( new Consumer()).start();

    }
}

package org.luzhen.test;

public class Produce implements Runnable {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        int count = 10;
        while (count > 0) {
            //用Test类中的public static final Object obj = new Object();对象作为锁,        
            //目的是:使得线程A 线程B公用一把锁
            synchronized (Test1.obj) {

                //System.out.print("count = " + count);
                System.out.println("A");
                count--;
            }

        }
    }
}

package org.luzhen.test;

public class Consumer implements Runnable {

    @Override
    public synchronized void run() {
        // TODO Auto-generated method stub
        int count = 10;
        while(count > 0) {
            //用Test类中的public static final Object obj = new Object();对象作为锁
            //目的是:使得线程A 线程B公用一把锁
            synchronized (Test1. obj) {

                System. out.println( "B");
                count --;
            }

        }
    }
}

输出结果:

A
A
A
A
A
A
A
A
A
B
B
B
B
B
B
B
B
B
B

Process finished with exit code 0

可以看到 主线程停止了:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值