MST

星途 面试题库

面试题:Java多线程环境下sleep和wait对锁的处理差异

在一个使用了synchronized关键字同步的代码块中,若线程A持有锁并调用了sleep方法,而线程B尝试获取该锁,会发生什么情况?同样场景下,若线程A调用的是wait方法,又会怎样?请深入分析这两种方法在多线程环境下对锁的处理机制以及对程序运行逻辑的影响。
14.2万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

synchronized 代码块中线程 A 调用 sleep 方法

  1. 锁的处理机制
    • 当线程 A 在 synchronized 代码块中调用 sleep 方法时,线程 A 并不会释放它所持有的锁。sleep 方法只是让线程进入睡眠状态,暂停执行一段时间,但它仍然占有锁。
    • 这是因为 sleepThread 类的静态方法,它不涉及到对象监视器(锁)的操作。
  2. 对程序运行逻辑的影响
    • 线程 B 尝试获取该锁时,由于线程 A 仍然持有锁,线程 B 会被阻塞,进入阻塞队列等待。直到线程 A 从 sleep 中醒来,执行完 synchronized 代码块并释放锁,线程 B 才有机会获取锁并继续执行。
    • 例如:
public class SleepInSync {
    private static final Object lock = new Object();

    public static void main(String[] args) {
        Thread A = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread A acquired the lock");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread A released the lock");
            }
        });

        Thread B = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread B acquired the lock");
            }
        });

        A.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        B.start();
    }
}

在这个例子中,线程 A 获得锁后睡眠 2 秒,在这 2 秒内线程 B 尝试获取锁会被阻塞,直到线程 A 醒来释放锁,线程 B 才能获取锁并执行。

synchronized 代码块中线程 A 调用 wait 方法

  1. 锁的处理机制
    • 当线程 A 在 synchronized 代码块中调用 wait 方法时,线程 A 会释放它所持有的锁。wait 方法是 Object 类的实例方法,它与对象监视器(锁)密切相关。
    • 线程 A 调用 wait 后,会进入该对象的等待队列,等待其他线程调用 notifynotifyAll 方法唤醒它。
  2. 对程序运行逻辑的影响
    • 线程 B 尝试获取该锁时,由于线程 A 已经释放了锁,线程 B 有机会获取锁并继续执行。
    • 例如:
public class WaitInSync {
    private static final Object lock = new Object();

    public static void main(String[] args) {
        Thread A = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread A acquired the lock");
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread A released the lock");
            }
        });

        Thread B = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread B acquired the lock");
                lock.notify();
            }
        });

        A.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        B.start();
    }
}

在这个例子中,线程 A 获得锁后调用 wait 释放锁并进入等待队列,线程 B 有机会获取锁,执行完后调用 notify 唤醒线程 A,线程 A 被唤醒后重新获取锁继续执行。

总结来说,sleep 方法不会释放锁,而 wait 方法会释放锁,这两种方法在多线程环境下对锁的处理和程序运行逻辑有显著不同。