【线程】sleep()与wait()区别

1.本文解决的问题

  1. wait()方法一定要使用sycronized进行同步吗?不用sycronized修饰会有什么问题?
  2. wait()方法会释放对象锁,那么这里指的锁是什么?
  3. wait()会释放对象锁,而sleep()不会释放对象锁,这在实际情况中有什么区别?

2. 结论

  1. sleep()方法可以在任何地方使用;
    wait()方法则只能在同步方法或同步块中使用;如果在non-synchronized函数或 non-synchronized block 中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。

  2. java中锁的概念很多,比如自旋锁重量级锁Synchronized偏向锁轻量级锁,由结论1得知wait()方法中的锁特指的是重量级锁Synchronized

    sycronized用法主要为修饰方法和代码块:

    在这里插入图片描述

  3. sleep()和wait()介绍

  • sleep()方法

    线程类(Thread)的静态方法,让调用的线程进入指定时间睡眠状态,使得当前线程进入阻塞状态,告诉系统至少在指定时间内不需要为线程调度器为该线程分配执行时间片,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。

    实际上,调用sleep()方法时并不要求持有任何锁,即sleep()可在任何地方使用

    当线程处于上锁时,sleep()方法不会释放对象锁,即睡眠时也持有对象锁。只会让出CPU执行时间片,并不会释放同步资源锁。

    睡眠时放弃cpu;如果持有锁,那么等待锁的其他线程仍然是等待状态。

    sleep()休眠时间满后,该线程不一定会立即执行,这是因为其他线程可能正在运行而起没有被调度为放弃执行,除非此线程具有更高的优先级。

    醒来后竞争cpu,只有重新竞争到cpu才能执行。

    在没有锁的情况下,sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会。

  • wait()方法

    是Object类里的方法,当一个线程执行wait()方法时,它就进入到一个和该对象相关的等待池中(进入等待队列,也就是阻塞的一种,叫等待阻塞),同时释放对象锁,并让出CPU资源,待指定时间结束后返还得到对象锁。

    wait()使用notify()方法、notiftAll()方法或者等待指定时间来唤醒当前等待池中的线程。等待的线程只是被激活,激活后需要重新竞争锁,必须得再次获得锁才能继续往下执行。竞争失败后进入block同步队列。

    可以参考 【线程】线程的5种状态详解中的同步队列与等待队列章节

3. 释放锁和不释放锁

wait()会释放对象锁,而sleep()不会释放对象锁,我们先用过例子来演示wait()释放锁。

我们启动2个线程,2个线程竞争锁lock对象,第一个获取锁的线程A会wait 10s,释放锁,第二个线程B会获取锁,通过日志打印的时间,可以发现B执行的时间和第一个线程A时间几乎相同,说明A释放锁后B才立即执行的,而不是A霸占锁并等待10s,等方法体执行完之后才轮到B执行的,否则B打印的时间应该=A的时间+10s

public class MyThread extends Thread {
    
    
    StringBuilder lock;

    public MyThread(StringBuilder lock) {
    
    
        this.lock = lock;
    }

    @Override
    public void run() {
    
    
        try {
    
    
            synchronized (lock) {
    
    
                System.out.println(getName() + "开始等待;当前时间秒数:" + Calendar.getInstance().getTime());
                lock.wait(10000); // 注意这里不是让lock进行wait,而是让当前线程进行wait
            }
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
    
    
        StringBuilder value = new StringBuilder();

        MyThread myThread1 = new MyThread(value);
        MyThread myThread2 = new MyThread(value);
        myThread1.start();
        myThread2.start();
    }
}

执行结果:

Thread-0开始等待;当前时间秒数:Tue Sep 29 `11:27:52` CST 2020
Thread-2开始等待;当前时间秒数:Tue Sep 29 `11:27:52` CST 2020

我们修改代码,验证sleep()不会释放对象锁:

// lock.wait(10000);   注释掉wait方法
sleep(10000);    //改为sleep

执行结果:

Thread-0开始等待;当前时间秒数:Tue Sep 29 `11:41:33` CST 2020
Thread-1开始等待;当前时间秒数:Tue Sep 29 `11:41:44` CST 2020

执行结果发现线程Thread-1与Thread-0相差10s,也就是说Thread-0在sleep时,别的竞争锁的线程仍然在等待,知道sleep结束,线程执行完后才会释放锁,别的线程才有获取锁的机会。

java的wait()方法使用注意事项 代码例子来源
java中的锁(一)(锁的介绍)
synchronized的使用以及原理

猜你喜欢

转载自blog.csdn.net/m0_45406092/article/details/108786091