线程间通信_等待/通知机制

等待/通知的相关方法式任意java对象都具备的,notify,wait方法被定义在java.lang.Object,都是final,不可重写



,是实例方法,新手比较容易出错的地方是,调用时候必须调用 锁对象.wait()/锁对象.nofity(),并且只能在临界区中调用

具体了解下,notify,wait定义

等待/通知方法
名称 描述
notify() 通知在同一个对象上等待的线程,使其从wait()方法返回,而返回的前提是该线程获取到对象的锁
notifyAll() 通知所有等待同一个对象锁的线程
wait() 调用该方法的线程进入WAITING状态,并且释放对象的锁,从方法描述上可以看出是响应中断的/或者接收到notify才会返回
wait(long) 超时等待一段时间,没有接受到通知就超时返回
wait(long,int) 对于超时时间更细粒度的控制,可以达到纳秒

等待/通知机制,举个例子来说线程A调用对象obj的wait方法进入WAITING状态,另一个线程调用同一个对象的notify方法唤醒线程A,线程A继续执行wait后的程序

简单的案例 ,单个生产者、单个消费者

锁对象:

package com.ftf.thread.test;

public class Student {
	public volatile boolean flag;
	public Student(boolean flag) {
		this.flag = flag;
	}
}

生产者:

package com.ftf.thread.test;

public class Product {
	private Student obj;

	public Product(Student obj) {
		this.obj = obj;
	}

	public void dothis() {
		synchronized (obj) {
			try{
				if(!obj.flag) {
					obj.wait();
				} 
					System.out.println("我是生产者线程"
							+ Thread.currentThread().getName());
					Thread.sleep(1000);
					obj.flag = false;
					obj.notify();
			}catch(InterruptedException e){
				e.printStackTrace();
			}
			
	}
}

}

消费者线程:

package com.ftf.thread.test;

public class Customer {
	private Student obj;

	public Customer(Student obj) {
		this.obj = obj;
	}

	public void dothis() {
		synchronized (obj) {
			try {
				if(obj.flag) {
					obj.wait();
				} 
				System.out.println("我是消费者线程"
						+ Thread.currentThread().getName());
				Thread.sleep(1000);
				obj.flag = true;
				obj.notify();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

main方法:

package com.ftf.thread.test;

public class NotifyWaitDemo {
	public static void main(String[] args) {
		Student obj = new Student(true);
		Product notify = new Product(obj);
		Customer wait = new Customer(obj);
		Thread1 t1 = new Thread1(notify);
		Thread2 t4 = new Thread2(wait);
		t1.start();
		t4.start();
	}
}
class Thread1 extends Thread{
	private Product notify;
	public Thread1(Product notify){
		this.notify= notify;
	}
	@Override
	public void run() {
		while(true){
			notify.dothis();
		}
	}
}
class Thread2 extends Thread{
	private Customer wait;
	public Thread2(Customer wait){
		this.wait = wait;
	}
	@Override
	public void run() {
		while(true){
			wait.dothis();
		}
	}
}

说明:

1.通过类Student flag定义为volatile这样,通过内存可见性,两个线程修改这个值,另一个线程都能看到,来控制两个线程释放锁和获取锁交互

2. 在单个消费者, 单个生产者和使用notify的情况下,使用if判断没有问题

多个生产者,多个消费者需要使用while作为条件判断

验证在多生产者消费者情况下,使用if存在的问题

生产者dothis方法修改:  while->if,因为是多个生产者消费者,需要将notify->notifyAll

public void dothis() {
		synchronized (obj) {
			try{
				if (!obj.flag) {
					obj.wait();
				} 
					System.out.println("我是生产者线程"
							+ Thread.currentThread().getName());
					Thread.sleep(1000);
					obj.flag = false;
					obj.notifyAll();
			}catch(InterruptedException e){
				e.printStackTrace();
			}
			
	}

同样,修改消费者代码

public void dothis() {
		synchronized (obj) {
			try {
				if (obj.flag) {
					obj.wait();
				} 
				System.out.println("我是消费者线程"
						+ Thread.currentThread().getName());
				Thread.sleep(1000);
				obj.flag = true;
				obj.notifyAll();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

,修改main方法:

public static void main(String[] args) {
		Student obj = new Student(true);
		Product notify = new Product(obj);
		Customer wait = new Customer(obj);
		Thread1 t1 = new Thread1(notify);
		Thread1 t2 = new Thread1(notify);
		Thread2 t3 = new Thread2(wait);
		Thread2 t4 = new Thread2(wait);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}

测试结果:

线程间通信_等待/通知机制_第1张图片

出现了,消费者线程连续消费两次的情况。

说明:

在多生产者,多消费者情况下,对于wait方法的判断使用while条件判断,而不是使用if,

是为了防止在多生产者,多消费者的情况下,如果使用if的条件,当前线程释放锁后,再次获取到锁后,

不进行检查flag,直接往下执行,那本例来说,就是消费者线程释放掉锁后,再次获取到锁,再次消费




你可能感兴趣的:(多线程,多线程学习)