Java多线程Day05-线程等待与唤醒

线程的等待与唤醒方法

  • Object.java中,定义了wait(), notify()notifyAll() 等接口:
    • wait()的作用:
      • 让当前线程进入等待状态
      • wait() 也会让当前线程释放所持有的锁
    • notify()和notifyAll()的作用:
      • 唤醒当前对象上等待的所有线程
      • notify() 是唤醒单个线程
      • notifyAll() 是唤醒所有线程
  • notify(): 唤醒此对象监视器上等待的单个线程
  • notifyAll(): 唤醒此对象监视器上等待的所有线程
  • wait(): 让当前线程处于等待或者堵塞状态,直到其余线程调用此对象的notify() 方法或者notifyAll() 方法,当前线程被唤醒进入就绪状态
  • wait(long timeout): 让当前线程处于等待或者阻塞状态,直到其余线程调用此对象的notify() 方法或者notifyAll() 方法,或者等待时间超过指定的时间,当前线程被唤醒进入就绪状态
  • wait(long timeout, int nanos): 让当前线程处于等待或者阻塞状态,直到其余线程调用此对象的notify() 方法或者notifyAll() 方法,或者其余某个线程中断当前线程,或者等待时间超过指定的时间,当前线程被唤醒进入就绪状态

wait()与notify()

class MyThread extends Thread {
	public MyThread(String name) {
		super(name);
	}

	public viod run() {
		synchronized(this) {
			System.out.println(Thread.currentThread().getName() + "调用notify()方法");
			// 唤醒当前的wait线程
			notify();
		}
	}
}

public class WaitTest {
	public static void main(String[] args) {
		Thread thread1 = new Thread("thread1");

		synchronized(thread1) {
			try {
				System.out.println(Thread.currentThread().getName() + "启动线程thread1");
				thread1.start();

				System.out.println(Thread.currentThread().getName() + "调用wait()方法");
				thread1.wait();

				System.out.println(Thread.currentThread().getName() + "继续执行");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
main启动线程thread1
main调用wait()方法
main调用notify()方法
main继续执行

在这里插入图片描述

  • 主线程代表主线程main. 线程t1代表WaitTest中启动的线程Thread1. 锁代表thread1对象的同步锁
  • 主线程main通过new Thread(“thread1”) 新建线程thread1. 然后通过synchronized(thread1) 获取对象的同步锁.接着调用thread1.start() 方法启动线程thread1
  • 主线程main执行thread1.wait() 释放 “thread1对象的锁” 并且进入 “等待或者阻塞状态”, 等待thread1对象上的线程通过notify() 或者notifyAll() 唤醒
  • 线程thread1运行之后,通过synchronized(this) 获取当前对象的锁,然后调用notify() 方法唤醒当前对象上的等待线程,即唤醒主线程main
  • 线程thread1运行结束后,释放当前对象的锁.然后主线程main获取thread对象的锁,接着运行
  • 问题: thread1.wait() 应该是让线程thread1等待,但是为什么让主线程main等待了?
    • wait() 作用是让 [当前线程] 等待 ,[当前线程] 是指正在CPU上运行的线程
    • 意味着尽管thread1.wait() 是通过线程thread1调用的wait() 方法,但是调用thread.wait() 的位置

wait(long timeout)与notify()

  • wait(long timeout) 会让当前线程处于等待阻塞状态,直到其余线程调用此对象的notify() 方法或notifyAll() 方法或者超过指定的时间量,当前线程被唤醒进入就绪状态
    在这里插入图片描述
  • 主线程main执行t1.start()启动线程t1
  • 主线程main执行t1.wait(3000), 主线程main进入阻塞状态. 需要使用t1对象锁的线程通过notify() 或者notifyAll() 唤醒或者超时3000ms之后自动唤醒,主线程进入就绪状态,然后才可以运行
  • 线程t1运行之后,进入循环会不断地运行
  • 超时3000ms之后,主线程main会进入就绪状态,然后接着进入运行状态

wait()与notifyAll()

  • notifyAll(): 唤醒此对象监视器上等待的所有线程
    在这里插入图片描述
  • 主线程新建并启动了3个线程t1, t2, t3
  • 主线程通过sleep(3000) 休眠3秒,在主线程休眠3秒的过程中,线程t1, t2, t3都运行了.运行的线程会执行obj.wait() 方法等待其余线程通过notify() 或者notifyAll() 来唤醒线程
  • 主线程休眠3秒之后,接着运行,执行obj.notifyAll() 唤醒obj上的等待线程,即等待的线程t1, t2, t3. 紧接着,主线程的synchronized(obj) 运行完毕之后,主线程释放obj锁,这样线程t1, t2, t3就可以获取obj锁继续运行

问题

  • notify()是依据什么唤醒等待线程的,即wait()和notify()之间是通过什么相互关联的?
    • 对象的同步锁
  • 为什么notify().wait()等函数方法定义在Object类中,而不是定义在Thread类中?
    • Object类中的wait()notify() 等函数方法是和synchronized一样,会对 [对象的同步锁] 进行操作
    • wait() 会使 [当前线程] 等待,因为线程进入等待状态,所以线程应该释放持有的 [对象的同步锁], 否则其余线程获取不到该 [对象的同步锁] 而无法运行
    • 线程调用wait() 之后,会释放持有的 [对象的同步锁], 等待线程被notify() 或者notifyAll() 唤醒
    • 负责唤醒等待线程的唤醒线程,只有在获取该对象的 [对象的同步锁], 即等待线程的同步锁,并且调用notify() 或者notifyAll() 方法之后,才能唤醒等待线程.被唤醒的等待线程进入就绪状态,不能立即执行.因为唤醒线程还持有着该对象的 [对象的同步锁], 必须等到唤醒线程释放了该对象的 [对象的同步锁] 之后,等待线程才能获取到该对象的 [对象的同步锁] 继续运行
    • 总的来说 ,notify(),wait() 等方法依赖于 [对象的同步锁],[对象的同步锁] 是对象持有的,并且每个对象有且仅有一个. 这就是notify(),wait() 等函数方法定义在Object类中而不是Thread类中的原因

猜你喜欢

转载自blog.csdn.net/JewaveOxford/article/details/108257283