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


    总的来说,线程的 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. }

    可以看到,线程 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. }

    如上所示,不使用 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. }

    使用 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. }

    因为在代码中有指定 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. }

  • 相关阅读:
    微服务12-分布式服务理论基础+Seata的认识
    QT信号槽实现原理
    开关电源怎么进行老化测试?有哪些测试方法?
    内部块拷贝函数memmove和memcpy总结
    ERROR: ld.so: object ‘/$LIB/libonion.so‘ from /etc/ld.so.preload
    java mysql体检管理系统源码
    中南林业科技大学Java实验报告九:内部类和异常类
    用Flask快速生成报表
    针对应用程序依赖库漏洞的攻击
    Linux基础篇(6)---》常用命令大全(网络命令+关机重启命令)
  • 原文地址:https://blog.csdn.net/jcc4261/article/details/127682162