Java并发--sleep()、wait()、notify()、notifyAll()方法详解

发布时间 2023-05-25 23:41:56作者: passionConstant

sleep()和wait方法比较 

基本差别:

1,sleep是Thread类中的native方法、wait是Object类中的方法。

/**
 * 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.
 *
 * @param  millis
 *         the length of time to sleep in milliseconds
 *
 * @throws  IllegalArgumentException
 *          if the value of {@code millis} is negative
 *
 * @throws  InterruptedException
 *          if any thread has interrupted the current thread. The
 *          <i>interrupted status</i> of the current thread is
 *          cleared when this exception is thrown.
 */
public static native void sleep(long millis) throws InterruptedException;
/**
 * Causes the current thread to wait until it is awakened, typically
 * by being <em>notified</em> or <em>interrupted</em>.
 * <p>
 * In all respects, this method behaves as if {@code wait(0L, 0)}
 * had been called. See the specification of the {@link #wait(long, int)} method
 * for details.
 *
 * @throws IllegalMonitorStateException if the current thread is not
 *         the owner of the object's monitor
 * @throws InterruptedException if any thread interrupted the current thread before or
 *         while the current thread was waiting. The <em>interrupted status</em> of the
 *         current thread is cleared when this exception is thrown.
 * @see    #notify()
 * @see    #notifyAll()
 * @see    #wait(long)
 * @see    #wait(long, int)
 */
public final void wait() throws InterruptedException {
    wait(0L);
}

2,sleep方法可以在任何地方使用,wait方法只能在synchronized方法或者synchronized块中使用。

 

主要区别:

1,Thread.sleep 只会让出cpu,不会导致锁行为改变。

2,Object.wait 不仅会让出cpu,还会释放占用的同步资源锁。其他线程可以得到锁。

wait传

 

demo:

public class WaitSleepDemo {
    public static void main(String[] args) {
        final Object lock = new Object();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread A is waiting to get lock");
                synchronized (lock){
                    try {
                        System.out.println("thread A get lock");
                        Thread.sleep(20);
                        System.out.println("thread A do wait method");
                        lock.wait(1000); //等待1000ms,让出cpu、锁
                        System.out.println("thread A is done");
                    } catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        try{
            Thread.sleep(10);
        } catch (InterruptedException e){
            e.printStackTrace();
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread B is waiting to get lock");
                synchronized (lock){
                    try {
                        System.out.println("thread B get lock");
                        System.out.println("thread B is sleeping 10 ms");
                        Thread.sleep(10);
                        System.out.println("thread B is done");
                    } catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        }).start();

    }
}

执行结果:

thread A is waiting to get lock
thread A get lock
thread B is waiting to get lock //A 的sleep方法不让出锁。B等待
thread A do wait method //A wait方法 让出锁,A
thread B get lock //A让出锁 B获得锁
thread B is sleeping 10 ms 
thread B is done //B执行完毕
thread A is done //A的wait(1000),到期自动唤醒,正好B释放锁。A可以得到锁

 可以看到,A虽然执行sleep方法,让出CPU,但不让出锁。如果不执行wait(1000)方法,B会一直等待获取锁。

wait方法,必须写在synchronized,因为必须要先获取锁,才能去释放锁。

 

 notify(),notifyAlll()方法:

上面demo中,通过wait(1000),设置参数1000ms后,A线程会自动唤醒。

也可以直接用wait(),不设置自动唤醒,可以在B线程中使用Object.notify()唤醒A线程。

demo:

 

 

两个概念(针对对象):

锁池entryList。B线程被阻塞,进入该对象的锁池,等待锁的释放,多个不同优先级的线程竞争锁,优先级高获取锁的概率大。

等待池WaitSet。不会去竞争锁。A调用wait()方法,会释放该对象的锁,同时进入等待池中,不竞争锁。