Java 多线程编程中的等待和休眠:wait() 和 sleep() 方法解析
背景
在Java多线程中,线程的状态如上图所示(图来自JavaGuide),可以发现,当前线程调用wait(long time)
方法或者执行Thread.sleep(long time)
方法都会进入到一个TIMED_WAITING
的状态。那么,这个状态下的线程的锁资源是怎么样的呢?
线程等待
在多线程环境下,如果当前线程调用了wait()方法,那么该方法会进入到WAITING
状态,并释放它所持有的锁,等待其他线程调用notify()
或notifyAll()
方法来唤醒它。如果没有其唤醒操作,当前线程会处于一个无限等待的状态。
如果当前线程在调用的是wait(long time)
方法时,线程会进入到一个TIMED_WAITING
状态,同时会释放锁资源,等待其他线程调用notify()
或notifyAll()
方法来唤醒它,或者等待指定的时间过期后自动唤醒。在等待期间,该线程不会占用 CPU 资源,因此其他线程可以执行。
代码演示:
WaitingThread类
1 | public class WaitingThread extends Thread { |
WaitingTest类
1 | public class WaitingTest { |
演示结果
上述代码中,我们创建了两个线程,并将它们传递给同一个锁对象。在run()
方法中,线程首先使用synchronized
关键字获取锁对象,然后调用wait(long time)
方法进入TIMED_WAITING
状态,等待2秒钟后会自动唤醒,此时,锁对象已经被释放,线程需要重新获取锁才能继续执行。可以看到,在线程重新获取锁之后,它就可以继续执行对共享数据的操作了。
线程休眠
当线程调用sleep(long time)
方法时,该线程也会进入到TIMED_WAITING
状态,但是当前线程对象并不会释放锁资源,因此其他线程对象也无法获取到锁资源,会进入阻塞状态。
当指定的休眠时间过期之后,当前线程会主动唤醒,并且该线程仍然持有锁资源,可以继续执行。
代码演示:
SleepingThread类
1 | public class SleepingThread extends Thread { |
SleepingTest类
1 | public class SleepingTest { |
运行结果
在上面的代码中,我们创建了两个线程,并将它们传递给同一个锁对象。在线程的run()方法中,我们首先使用synchronized关键字来获取锁对象,然后让线程进入TIMED_WAITING状态。在这里,线程会休眠2秒钟,然后再输出一条消息。
总结
当线程调用wait()
方法时,线程会进入一个WAITING
状态,并且释放锁资源,直至被唤醒才会进入到就绪状态,竞争锁资源。
当线程调用wait(long time)
方法时(指定一个等待时间),线程会进入到一个TIMED_WAITING
状态,同时释放锁资源,只有当线程被通知或者等待时间结束后才会重新去获取锁资源。
当线程调用的是sleep(long time)
方法,线程虽然也会进入到一个TIMED_WAITING
状态,但是不会释放锁资源,其他线程会处于阻塞状态直至当前线程释放锁资源