二、了解 Java 多线程 (入门篇)

 

今天,来聊一聊线程的 sleep() 方法和 wait() 方法的区别:

首先,先看源码:

可以看出,sleep() 方法是 Thread 类的方法,底层是直接调用的 C++文件去执行线程的 sleep();

而wait()方法则是 Object类的方法,而我们知道,Java中Object类是所有类的父类,也就意味着,所有的类都有 wait() 方法。wait()方法的底层也是调用的 C++ 文件的方法去执行。

共同点:sleep()方法与 wait()方法都可以让线程暂停一段时间:

public class OrderAppTest {

    public static void main(String[] args) {
        Test test = new Test();
        System.out.println("mainThread beginTime:" + System.currentTimeMillis());
        test.start();
    }
}

class Test extends Thread {

    @Override
    public void run() {
        try {
            sleep(5000);
            System.out.println("Runnable beginTime:" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 sleep()方法停止线程的效果如下:

再来看 wait() 方法的效果:

public class OrderAppTest {
    public static Object object = new Object();

    public static void main(String[] args) {
       synchronized (object){
           System.out.println("mainThread beginTime:" + System.currentTimeMillis());
           try {
               object.wait(5000);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println("mainThread endTime:" + System.currentTimeMillis());
       }
    }
}

运行效果图如下:

从代码的运行效果上看,sleep() 方法和 wait() 方法都具备使线程暂停一段时间的效果。【可能有些初学者看不懂wait()的使用示例代码,稍后,我会介绍 synchronized 关键字和 wait() 方法的使用方法】

 

不同点:sleep() 方法暂停期间,不会释放锁,而 wait() 方法被执行后,会立即释放锁,关于锁的理解,请看这篇文章:【https://blog.csdn.net/shizhiqian0021/article/details/106062934

照例,通过一段测试代码来理解一下:

public class OrderAppTest {

    public static void main(String[] args) {
        Test test = new Test();
        Thread a = new Thread(test, "A");
        Thread b = new Thread(test, "B");
        a.start();
        b.start();
    }
}
class Test extends Thread{
    @Override
    synchronized public void run() {
        System.out.println(currentThread().getName() + "线程,BeginTime:" + System.currentTimeMillis());
        try {
            sleep(5000 );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(currentThread().getName() + "线程,EndTime:" + System.currentTimeMillis());
    }
}

运行该段代码,打印结果如下:

从运行结果可以看出,在A线程sleep()期间,B线程拿不到锁,无法进入run()方法;由此,得出结论:sleep()方法暂停期间,线程是不释放锁的。

下面我们来看 wait() 方法:

public class OrderAppTest {

    public static void main(String[] args) {
        Test test = new Test(new Object());
        Thread a = new Thread(test, "A");
        Thread b = new Thread(test, "B");
        a.start();
        b.start();
    }
}
class Test extends Thread{
    private Object object;

    public Test(Object object) {
        this.object = object;
    }

    @Override
    public void run() {
        synchronized (object){
            System.out.println(currentThread().getName() + "线程,BeginTime:" + System.currentTimeMillis());
            try {
                object.wait(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(currentThread().getName() + "线程,EndTime:" + System.currentTimeMillis());
        }
    }
}

运行该段代码,打印结果如下:

从运行结果可以看出,A线程开始以后,执行到 object.wait(5000)处,A线程停止5秒,同时立即释放锁,这时,等待获取object对象锁的B线程获得锁,开始执行,同样执行到object.wait(5000)处,B线程停止5秒,同时,释放锁;A线程苏醒,获得锁,继续执行wait()之后的代码,执行完成,A线程释放锁;B线程苏醒后,A线程已经执行完成并释放锁,B线程重新获得锁,继续执行wait()之后的代码,执行完成,B线程释放锁,程序运行结束。故,得出结论:wait() 暂停期间,会释放锁,当暂停时间结束后,线程会重新去争夺锁,然后继续运行wait()方法之后的代码。

 

接下来,我们继续看一下wait()方法:wait()方法的JDK源码其实已经讲的很清楚了:

    /**
     * @param      timeout   the maximum time to wait in milliseconds.
     * @throws  IllegalArgumentException      if the value of timeout is
     *               negative.
     * @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 for a notification.  The <i>interrupted
     *             status</i> of the current thread is cleared when
     *             this exception is thrown.
     * @see        java.lang.Object#notify()
     * @see        java.lang.Object#notifyAll()
     */
    public final native void wait(long timeout) throws InterruptedException;

 

我们看,方法注解里抛出的第二个异常说明:翻译一下就是:

如果当前线程不是对象监视器的所有者(这里所说的对象监视器即:锁)。则会抛出 IllegalMonitorStateException 异常。也就是说,调用wait()方法,必须持有对象锁,否则会抛出异常。

而调用sleep()方法则不需要持有对象锁。

    /**     
     * @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;

注意看wait()方法和sleep()方法的注解,两个方法抛出的异常中,sleep()方法不会抛出 IllegalMonitorStateException异常,也就是说,调用sleep()方法时,是否持有对象锁其实无所谓,都不会报错。

 

最后,总结一下:

wait() 与 sleep() 的相同点:

都可以使线程暂停一段时间。

不同点:

sleep()方法是 Thread 类的方法,wait()方法是 Object 类的方法。

调用sleep()不需要当前线程持有对象锁,而wait()方法则需要当前线程必须持有对象锁,否则抛出 IllegalMonitorStateException 异常。

如果调用sleep() 方法的线程持有锁的话,sleep()方法被调用后,该线程不会释放锁,会等待sleep()暂停时间之后,继续执行其后的代码。而wait()方法则会立即释放锁,然后当wait()暂停时间之后,回去重新争夺锁,然后再继续执行wait()之后的代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值