线程的 sleep() 方法与 wait() 方法的区别

朴灿烈づ我的快乐病毒、 2023-09-27 12:28 135阅读 0赞

总的来说,线程的 sleep() 方法和 wait() 方法有以下几点区别:

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

(2)sleep() 方法不会释放 lock,但是 wait() 方法会释放,而且会加入到等待队列中。

(3)sleep() 方法不依赖于同步器 synchronized(),但是 wait() 方法 需要依赖 synchronized 关键字。

(4)线程调用 sleep() 之后不需要被唤醒(休眠时开始阻塞,线程的监控状态依然保持着,当指定的休眠时间到了就会自动恢复运行状态),但是 wait() 方法需要被重新唤醒(不指定时间需要被别人中断)。

  1. public class SleepDemo {
  2. public static final Object LOCK = new Object();
  3. public static void main(String[] args) {
  4. Stream.of("线程1", "线程2").forEach(a -> new Thread(a) {
  5. @Override
  6. public void run() {
  7. new SleepDemo().testSleep();
  8. }
  9. }.start());
  10. }
  11. private void testSleep() {
  12. synchronized (LOCK) {
  13. try {
  14. System.out.println(Thread.currentThread().getName() + "正在执行: " + System.currentTimeMillis() / 1000);
  15. // 休眠 2 s
  16. Thread.sleep(2000);
  17. System.out.println(Thread.currentThread().getName() + "恢复执行: " + System.currentTimeMillis() / 1000);
  18. } catch (Exception e) {
  19. }
  20. }
  21. }
  22. }

f412c41c9a4e121c4dd9188c11f181c8.png

可以看到,线程 1 先抢到了资源,执行主体方法时要求睡眠 2 秒,那么在这两秒时间内,即使线程 1 没有任何动作,线程 2 也不能抢占资源。 需要注意的是,在调用 sleep() 方法时,如果有两个线程,那么要想实现线程睡眠的效果就需要使用 synchronized() 方法,否则达不到效果。

  1. public class SleepDemo {
  2. // public static final Object LOCK = new Object();
  3. public static void main(String[] args) {
  4. Stream.of("线程1", "线程2").forEach(a -> new Thread(a) {
  5. @Override
  6. public void run() {
  7. new SleepDemo().testSleep();
  8. }
  9. }.start());
  10. }
  11. private void testSleep() {
  12. // synchronized (LOCK) {
  13. try {
  14. System.out.println(Thread.currentThread().getName() + "正在执行: " + System.currentTimeMillis() / 1000);
  15. // 休眠 2 s
  16. Thread.sleep(2000);
  17. System.out.println(Thread.currentThread().getName() + "恢复执行: " + System.currentTimeMillis() / 1000);
  18. } catch (Exception e) {
  19. System.out.println(e);
  20. }
  21. // }
  22. }
  23. }

f53f1896f08bfe148ec48c739e4369cd.png

如上所示,不使用 synchronized() 的话就会出现两个线程同时执行,同时睡眠,又同时恢复执行。

由此可知,调用 sleep() 方法时,并不是强依赖于 synchronized() 方法,如果我只有一个线程,那么使用 synchronized() 方法和不使用 synchronized() 方法的效果是一样的。如果有两个线程的话,也可以选择使用或者不使用 synchronized() 方法。但是 wait() 方法就不一样了,wait() 方法强依赖于 synchronized() 方法,如果不使用 synchronized() 方法的话,wait() 方法的程序就会报错。

  1. public class WaitDemo {
  2. public static final Object LOCK = new Object();
  3. public static void main(String[] args) {
  4. Stream.of("线程1", "线程2").forEach(a -> new Thread(a) {
  5. @Override
  6. public void run() {
  7. WaitDemo.testWait();
  8. }
  9. }.start());
  10. }
  11. private static void testWait() {
  12. // synchronized (LOCK) {
  13. try {
  14. System.out.println(Thread.currentThread().getName() + "正在执行: " + System.currentTimeMillis() / 1000);
  15. // 等待 2 s
  16. LOCK.wait(2000);
  17. System.out.println(Thread.currentThread().getName() + "恢复执行: " + System.currentTimeMillis() / 1000);
  18. } catch (InterruptedException e) {
  19. System.out.println(e);
  20. }
  21. }
  22. // }
  23. }

12e840debecbff20b38797e60de69659.png

使用 synchronized 关键字修饰后:

  1. public class WaitDemo {
  2. public static final Object LOCK = new Object();
  3. public static void main(String[] args) {
  4. Stream.of("线程1", "线程2").forEach(a -> new Thread(a) {
  5. @Override
  6. public void run() {
  7. WaitDemo.testWait();
  8. }
  9. }.start());
  10. }
  11. private static void testWait() {
  12. synchronized (LOCK) {
  13. try {
  14. System.out.println(Thread.currentThread().getName() + "正在执行: " + System.currentTimeMillis() / 1000);
  15. // 等待 2 s
  16. LOCK.wait(2000);
  17. System.out.println(Thread.currentThread().getName() + "恢复执行: " + System.currentTimeMillis() / 1000);
  18. } catch (InterruptedException e) {
  19. System.out.println(e);
  20. }
  21. }
  22. }
  23. }

333cf1f9b0966cd86b60259f1ba86314.png

因为在代码中有指定 wait(2000),所以当 2 秒之后该线程就会恢复执行的,而不用另外一个线程去唤醒,如果 wait() 方法没有指定时间的话,那么该线程就会一直等待~

除此之外,一个线程一旦被 wait 之后,就必须有另外一个线程去唤醒,否则一直处于等待状态。

  1. public class WaitDemo {
  2. public static final Object LOCK = new Object();
  3. private void testWait1() {
  4. synchronized (LOCK) {
  5. try {
  6. System.out.println(Thread.currentThread().getName() + "开始执行: " + System.currentTimeMillis() / 1000);
  7. LOCK.wait();
  8. System.out.println(Thread.currentThread().getName() + "恢复执行: " + System.currentTimeMillis() / 1000);
  9. } catch (Exception e) {
  10. System.out.println(e);
  11. }
  12. }
  13. }
  14. private void testNotify() {
  15. synchronized (LOCK) {
  16. try {
  17. Thread.sleep(2000);
  18. LOCK.notify();
  19. System.out.println(Thread.currentThread().getName() + "唤醒另一线程: " + System.currentTimeMillis() / 1000);
  20. } catch (Exception e) {
  21. System.out.println(e);
  22. }
  23. }
  24. }
  25. public static void main(String[] args) {
  26. new Thread() {
  27. @Override
  28. public void run() {
  29. new WaitDemo().testWait1();
  30. }
  31. }.start();
  32. new Thread() {
  33. @Override
  34. public void run() {
  35. new WaitDemo().testNotify();
  36. }
  37. }.start();
  38. }
  39. }

176448505119a4c582c86077dc3fff56.png

发表评论

表情:
评论列表 (有 0 条评论,135人围观)

还没有评论,来说两句吧...

相关阅读