【转载】wait和notify在锁竞争中的执行顺序

本文详细解析了Java中线程的sleep与wait方法的区别及应用实例。通过具体代码演示了如何使用这两种方法来控制线程的行为,包括如何让线程暂停执行以及如何释放同步锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:http://blog.youkuaiyun.com/wxwzy738/article/details/8628443

sleep就是正在执行的线程主动让出cpu,cpu去执行其他线程,在sleep指定的时间过后,cpu才会回到这个线程上继续往下执行,如果当前线程进入了同步锁,sleep方法并不会释放锁,即使当前线程使用sleep方法让出了cpu,但其他被同步锁挡住了的线程也无法得到执行。wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放。如果notify方法后面的代码还有很多,需要这些代码执行完后才会释放锁,可以在notfiy方法后增加一个等待和一些代码,看看效果),调用wait方法的线程就会解除wait状态和程序可以再次得到锁后继续向下运行。

[java]  view plain copy
  1. public class MultiThread {  
  2.     /** 
  3.      * @param args 
  4.      */  
  5.     public static void main(String[] args) {  
  6.         new Thread(new Thread1()).start();  
  7.         try {  
  8.             Thread.sleep(10);  
  9.         } catch (InterruptedException e) {  
  10.             e.printStackTrace();  
  11.         }  
  12.         new Thread(new Thread2()).start();  
  13.     }  
  14.   
  15.     private static class Thread1 implements Runnable {  
  16.   
  17.         @Override  
  18.         public void run() {  
  19.             // 由于这里的Thread1和下面的Thread2内部run方法要用同一对象作为监视器,我们这里不能用this,因为在Thread2里面的this和这个Thread1的this不是同一个对象。我们用MultiThread.class这个字节码对象,当前虚拟机里引用这个变量时,指向的都是同一个对象。  
  20.             synchronized (MultiThread.class) {  
  21.   
  22.                 System.out.println("enter thread1...");  
  23.                 System.out.println("thread1 is waiting");  
  24.                 try {  
  25.                     // 释放锁有两种方式,第一种方式是程序自然离开监视器的范围,也就是离开了synchronized关键字管辖的代码范围,另一种方式就是在synchronized关键字管辖的代码内部调用监视器对象的wait方法。这里,使用wait方法释放锁。  
  26.                     MultiThread.class.wait();  
  27.                 } catch (InterruptedException e) {  
  28.                     e.printStackTrace();  
  29.                 }  
  30.   
  31.                 System.out.println("thread1 is going on...");  
  32.                 System.out.println("thread1 is being over!");  
  33.             }  
  34.         }  
  35.   
  36.     }  
  37.   
  38.     private static class Thread2 implements Runnable {  
  39.   
  40.         @Override  
  41.         public void run() {  
  42.             synchronized (MultiThread.class) {  
  43.   
  44.                 System.out.println("enter thread2...");  
  45.                 System.out.println("thread2 notify other thread can release wait status..");  
  46.                 // 由于notify方法并不释放锁,  
  47.                 // 即使thread2调用下面的sleep方法休息了10毫秒,但thread1仍然不会执行,因为thread2没有释放锁,所以Thread1无法得不到锁。  
  48.                 //notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放。如果notify方法后面的代码还有很多,需要这些代码执行完后才会释放锁  
  49.                 MultiThread.class.notify();  
  50.                 System.out.println("thread2 is sleeping ten millisecond...");  
  51.                 try {  
  52.                     Thread.sleep(10);  
  53.                 } catch (InterruptedException e) {  
  54.                     e.printStackTrace();  
  55.                 }  
  56.                 System.out.println("thread2 is going on...");  
  57.                 System.out.println("thread2 is being over!");  
  58.             }  
  59.         }  
  60.   
  61.     }  
  62.     /** 
  63.      * 运行结果: 
  64.      *  enter thread1... 
  65.         thread1 is waiting 
  66.         enter thread2... 
  67.         thread2 notify other thread can release wait status.. 
  68.         thread2 is sleeping ten millisecond... 
  69.         thread2 is going on... 
  70.         thread2 is being over! 
  71.         thread1 is going on... 
  72.         thread1 is being over! 
  73.      */  
  74. }  


<think>嗯,用户想了解Java中waitnotify执行顺序,并希望看到具体的例子。首先,我得回忆一下waitnotify的基本机制。这两个方法都是Object类中的,用于线程间的协调。wait()会让当前线程进入等待状态,并释放,直到其他线程调用notify()或notifyAll()来唤醒它。而notify()会随机唤醒一个在等待该对象的线程,notifyAll()则唤醒所有等待的线程。 用户的问题是关于执行顺序的,可能需要解释在多线程环境下,waitnotify是如何协作的,以及代码的执行流程。比如,当线程A调用wait()后,它会释放,然后线程B可以获取执行notify(),唤醒线程A。但被唤醒的线程A需要重新获得才能继续执行。 接下来,我需要找一个合适的例子来说明这个过程。可能需要两个线程,一个执行wait,另一个执行notify。比如,主线程启动另一个线程后,先获取,调用wait(),然后另一个线程在某个条件满足时调用notify()唤醒主线程。 不过,用户提供的引用中有几个代码示例,比如引用1引用2中的例子都是单线程中调用wait(),但这样可能无法展示notify的作用,因为没有其他线程来唤醒。所以正确的例子应该包含两个线程,一个等待,另一个通知。 例如,可以设计一个场景,主线程启动一个工作线程,主线程先获取,调用wait(),然后工作线程在完成某些任务后调用notify()。这样主线程会被唤醒,继续执行。 另外,需要注意synchronized块的使用,确保waitnotify都是在持有对象的情况下调用,否则会抛出IllegalMonitorStateException。同时,在调用wait()后,线程会释放,允许其他线程进入同步块。 在示例中,应该展示两个线程交替执行的过程,并说明每一步的执行顺序的状态。比如: 1. 主线程获取,打印“等待前”,调用wait(),释放,进入等待状态。 2. 工作线程随后获取执行任务,调用notify(),唤醒主线程,但工作线程需要退出同步块后,主线程才能重新获取继续执行。 3. 主线程被唤醒后,需要重新获得,然后继续执行后面的代码。 同时,可能还需要处理InterruptedException,但示例中可以暂时忽略,或者加上throws声明。 需要确保示例代码正确,不会出现死,并且能够清晰展示执行顺序。另外,要解释代码的执行流程,比如为什么工作线程的notify()之后,主线程不会立即执行,而是需要等工作线程释放之后。 最后,可能还需要总结执行顺序的关键点,比如wait释放notify后唤醒线程需要重新获取等。以及常见问题,如忘记获取,或者多个线程的情况。 可能用户还关心为什么有时候notify()之后,等待的线程没有立即执行,或者多个等待线程时的行为,这时候需要提到notify()随机唤醒一个,而notifyAll()唤醒所有,但只有一个能获取。 总之,需要构造一个清晰的双线程示例,展示waitnotify执行顺序,并解释每个步骤,确保用户理解线程间的协作的获取与释放过程。</think>### Java中waitnotify执行顺序解析 在Java中,`wait()``notify()`是线程间协作的核心方法,其执行顺序依赖于**的获取与释放**机制。以下是具体分析及示例: --- #### 1. 基本执行流程 1. **调用`wait()`的线程**: - 释放对象,进入等待状态。 - 需被其他线程通过`notify()`或`notifyAll()`唤醒。 - 唤醒后需**重新竞争**才能继续执行后续代码[^3][^4]。 2. **调用`notify()`的线程**: - 唤醒一个等待线程(随机选择),但自身**不会立即释放**。 - 只有当前线程退出同步块后,被唤醒的线程才能继续执行[^1]。 --- #### 2. 代码示例:双线程协作 ```java public class WaitNotifyExample { public static void main(String[] args) throws InterruptedException { Object lock = new Object(); // 线程A:等待并释放 Thread threadA = new Thread(() -> { synchronized (lock) { System.out.println("线程A:获取,调用wait()"); try { lock.wait(); // 释放,进入等待 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程A:被唤醒,继续执行"); } }); // 线程B:唤醒线程A Thread threadB = new Thread(() -> { synchronized (lock) { System.out.println("线程B:获取,调用notify()"); lock.notify(); System.out.println("线程B:通知完成,但尚未释放"); try { Thread.sleep(2000); // 模拟耗时操作 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程B:释放"); } }); threadA.start(); Thread.sleep(100); // 确保线程A先启动 threadB.start(); } } ``` --- #### 3. 执行顺序详解 1. **线程A启动**: - 获取`lock`,调用`wait()`后**释放**并进入等待。 - 输出:`线程A:获取,调用wait()`。 2. **线程B启动**: - 获取`lock`(此时线程A已释放),调用`notify()`唤醒线程A。 - **线程A被唤醒后需等待线程B退出同步块才能重新获取**。 - 输出:`线程B:获取,调用notify()` → `线程B:通知完成,但尚未释放` → `线程B:释放`。 3. **线程A恢复执行**: - 线程B释放后,线程A重新获取,继续执行剩余代码。 - 输出:`线程A:被唤醒,继续执行`。 --- #### 4. 关键点总结 - **的释放与竞争**:`wait()`会释放,`notify()`不会立即释放。 - **线程调度**:被唤醒的线程需重新竞争,且不能保证立即执行。 - **避免死**:确保所有`wait()`都有对应的`notify()`逻辑。 - **多线程场景**:若存在多个等待线程,`notify()`随机唤醒一个,而`notifyAll()`唤醒所有。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值