Java线程的wait() 与notify()

本文详细介绍了Java中线程同步的基本概念,包括synchronized关键字、wait()与notify()方法的使用,以及它们如何帮助实现线程间的正确同步。通过具体的代码示例展示了不同情况下线程的执行流程。

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

       java会为每个object对象分配一个monitor,当某个对象的同步方法(synchronized methods )被多个线程调用时,该对象的monitor将负责处理这些访问的并发独占要求。

wait() 的方法是Object的方法,不是线程的方法,作用是让线程挂起,处于等待状态,之后可以调用notify()的方法激活线程。

      也可以这样使用,线程处于运行时,判断到某个状态时调用wait(),这样线程处于等待状态,在其他地方调用object的notify的方法时,也必须获取到该线程的同步锁:

synchronized (object) {
	boject.notify();										
}

       对于notify()方法,如果多个线程处于等待状态,那么被唤醒的线程由VM选择决定,调用了notify的线程将放弃对对象的锁,其他线程会尝试获得该对象的锁,获得该锁的对象将被唤醒:


notify()、wait()的方法必须要在获得锁的情况下使用,比如说在同步代码里面:

synchronized (object) {
	boject.notify();										
}



所以注意的是:

1.wait()与notify()的方法是object的共同属性,此时object当成一个同步锁。

2.wait()的方法会让线程挂起并释放锁,而notify()的方法会将挂起的线程唤醒同时在同步代码块结束后释放锁。

3.wait()与notify的方法是已经获取了锁的情况下,获取对象的monitor的方法有:

    a.执行这个object的synchronized方法。

   b.执行一段synchronized代码,并基于这个object的同步。

   c.如果boject是class类,可以执行它的synchronized static 方法。

简单理解:wait()与notify()都是获取到同步锁的情况下才能执行的,语法上就是写在synchronized中。wait()的作用是放弃同步锁并使线程进入休眠,直到其他线程获取到同步锁使用notify()后才唤醒。Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制。

使用:

1.同步锁的理解

  启动十个线程线程,代码如下:

	public static void main(String[] args) {

		Object a = new Object();

		for (int i = 0; i < 10; i++) {
			new Thread(new test2(a, i + "")).start();
		}

	}

	public static class test2 implements Runnable {
		Object lock;
		String name;

		public test2(Object lock, String name) {
			this.lock = lock;
			this.name = name;
		}

		public void run() {

			System.out.println(name + "开始执行");
			double f = 66;
			while (f < 30000000.0) {
				f = f + 0.05;
			}
			System.out.println(name + "结束执行");

		}
	}

执行结果如下:

2开始
0开始
7开始
4开始
6开始
8开始
3开始
1开始
5开始
9开始
8结束
5结束
4结束
0结束
2结束
6结束
3结束
1结束
7结束
9结束

总结:十个线程执行差不多是同时执行的,因为在循环过程中执行了耗时操作,所以所有线程执行了开始执行后才会执行结束执行操作,最先开始的不一定最先结束,因为是使用cup是随机抢占的。


加了同步锁:

public static class test2 implements Runnable {
		Object lock;
		String name;

		public test2(Object lock, String name) {
			this.lock = lock;
			this.name = name;
		}

		public void run() {

			synchronized (lock) {
				System.out.println(name + "开始");
				double f = 66;
				while (f < 30000000.0) {
					f = f + 0.05;
				}

				System.out.println(name + "结束");
			}

		}
	}

执行结果如下:

0开始
0结束
4开始
4结束
3开始
3结束
2开始
2结束
1开始
1结束


总结
:进行同步后,其他线程会等待已经获取到同步锁的线程完成操作并将同步锁释放,释放后线程随机去抢同步锁,获取到同步锁的线程才能执行。


让线程执行了开始后就调用wait()

public static class test2 implements Runnable {
		Object lock;
		String name;

		public test2(Object lock, String name) {
			this.lock = lock;
			this.name = name;
		}

		public void run() {

			synchronized (lock) {

				System.out.println(name + "开始");

				try {
					//放弃锁并使当前线程休眠
					lock.wait();
				} catch (InterruptedException e) {

					e.printStackTrace();
				}

				double f = 66;
				while (f < 30000000.0) {
					f = f + 0.05;
				}

				System.out.println(name + "结束");
			}

		}
	}

打印结果如下:

0开始
2开始
1开始
3开始
4开始

总结:所有线程都调用了wait()后暂停了,由于没有唤醒所以都没有执行下面的操作。


让其中一个线程唤醒其他线程:

public static class test2 implements Runnable {
		Object lock;
		String name;

		public test2(Object lock, String name) {
			this.lock = lock;
			this.name = name;
		}

		public void run() {

			synchronized (lock) {

				System.out.println(name + "开始");

				try {
                                //如果是第四个线程,唤醒其他的线程
					if (name.equals("4")) {
						lock.notifyAll();
						//lock.wait();如果加了这个后,第四个线程不会执行下面的操作
					} else {
						// 放弃锁并使当前线程休眠
						lock.wait();
					}

				} catch (InterruptedException e) {

					e.printStackTrace();
				}

				double f = 66;
				while (f < 30000000.0) {
					f = f + 0.05;
				}

				System.out.println(name + "结束");
			}

		}
	}


打印如下:

0开始
2开始
1开始
3开始
4开始
4结束
3结束
1结束
2结束
0结束

总结:唤醒其他线程后,那些线程将随机抢占同步锁执行下面的操作。值得注意的是,notify的方法是唤醒其他线程但是不会立即放弃同步锁,wait()是会立即放弃同步锁的。


转载注明出处:http://blog.youkuaiyun.com/u014614038/article/details/49020147



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值