线程之间的通信(wait()/notify()机制)——等待唤醒机制

wait() : 使当前同步监视器上的线程进入等待状态, 同时释放锁     对象名.wait()
notify() / notifyAll() : 唤醒当前同步监视器上等待状态的一个(所有)线程    对象名.notify()
-------------------- 上述方法必须使用在同步方法中(必须在加锁的状态)

wait(),notify();notifyAll()这些方法定义在object类原因是琐是任意对象,而这几个方法又必须用在锁当中

例1:使用两个线程,交替打印1-100

public class PrintRunnable implements Runnable {

	int i = 0;

	@Override
	public synchronized void run() {
		while (true) {
			notify();//唤醒等待的线程
			if (i < 100) {
				System.out.println(Thread.currentThread().getName() + ":" + i++);
			}
			try {
				wait();//等待 同时释放锁
			} catch (InterruptedException e) {
			}
		}
	}
}
public class MyTest {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//线程执行体 下面的线程传入同一个runnable
		PrintRunnable printRunnable = new PrintRunnable();

		//两个线程执行打印
		Thread print1 = new Thread(printRunnable, "打印者1");
		Thread print2 = new Thread(printRunnable, "打印者2");

		//开始打印
		print1.start();
		print2.start();
	}
}

例2:模拟售票程序,实现三个窗口同时卖100张票

public class Tickets implements Runnable {

	int tick = 100;
	Object object = new Object();

	@Override
	public void run() {
		while (true) {
			synchronized (object) {
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//将操作共享变量的代码块放入同步监视器里
				if (tick > 0) {
					tick--;
					System.out.println(Thread.currentThread().getName() + "完成售票,余票为 :" + tick);
				}
			}
		}
	}
}
public class MyTest {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//线程执行体 下面的几个线程 构造器传入同一个runnable 所以共享变量不需要static修饰也可以
		Tickets tickets = new Tickets();

		//三个窗口 三个线程
		Thread win1 = new Thread(tickets, "窗口1");
		Thread win2 = new Thread(tickets, "窗口2");
		Thread win3 = new Thread(tickets, "窗口3");

		//开始卖票
		win1.start();
		win2.start();
		win3.start();

	}
}

例3:生产者消费者问题

店员拥有产品属性

public class Clerk {
	//属性 店员的产品
	private int product;

	// 公共的get/set方法
	public int getProduct() {
		return product;
	}

	public void setProduct(int product) {
		this.product = product;
	}

	// 无参和全参构造器
	public Clerk() {}

	public Clerk(int product) {
		this.product = product;
	}

	// 生产商送货的方法
	public synchronized void getproducts() {
		if (product >= 20) {
			System.out.println("货物已满");
			try {
				wait();
			} catch (InterruptedException e) {
			}
		} else {
			System.out.println(Thread.currentThread().getName() + "成功送来第" + ++product + "号货物");
			notifyAll();
		}
	}

	// 消费者取走货物的方法
	public synchronized void takeOffproduct() {
		if (product <= 0) {
			System.out.println("已缺货!!!");
			try {
				wait();
			} catch (InterruptedException e) {
			}
		} else {
			System.out.println(Thread.currentThread().getName() + "成功取走第" + product-- + "号货物");
			notifyAll();
		}
	}
}

生产者

public class Productor implements Runnable{
	private Clerk clerk;

	// 公共的get/set方法
	public Clerk getClerk() {
		return clerk;
	}

	public void setClerk(Clerk clerk) {
		this.clerk = clerk;
	}

	// 无参和全参构造器
	public Productor() {
	}

	public Productor(Clerk clerk) {
		this.clerk = clerk;
	}

	//实现接口的run方法执行体
	@Override
	public void run() {
		while (true) {
			clerk.getproducts();
		}
	}
}

消费者

public class Customer implements Runnable{
	private Clerk clerk;

	// 公共的get/set方法
	public Clerk getClerk() {
		return clerk;
	}

	public void setClerk(Clerk clerk) {
		this.clerk = clerk;
	}

	// 无参和全参构造器
	public Customer() {
	}

	public Customer(Clerk clerk) {
		this.clerk = clerk;
	}

	// 消费者取走货物的方法,实现接口run方法执行体
	@Override
	public void run() {
		while (true) {
			clerk.takeOffproduct();
		}
	}
}

test

public class MyTest {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//店员 拥有产品属性
		Clerk clerk = new Clerk();
		//生产者 生产执行体
		Productor productor = new Productor(clerk);
		//消费者消费执行体
		Customer customer = new Customer(clerk);
		//生产产品的线程
		Thread pro = new Thread(productor, "生产者");
		//消费产品的线程
		Thread cus = new Thread(customer, "消费者");
		pro.start();//生产产品开始
		cus.start();//消费产品开始
	}
}

测试结果

消费者成功取走第20号货物
消费者成功取走第19号货物
消费者成功取走第18号货物
消费者成功取走第17号货物
消费者成功取走第16号货物
消费者成功取走第15号货物
消费者成功取走第14号货物
消费者成功取走第13号货物
消费者成功取走第12号货物
消费者成功取走第11号货物
消费者成功取走第10号货物
消费者成功取走第9号货物
消费者成功取走第8号货物
消费者成功取走第7号货物
消费者成功取走第6号货物
消费者成功取走第5号货物
消费者成功取走第4号货物
消费者成功取走第3号货物
消费者成功取走第2号货物
消费者成功取走第1号货物
已缺货!!!
生产者成功送来第1号货物
生产者成功送来第2号货物
生产者成功送来第3号货物
生产者成功送来第4号货物
生产者成功送来第5号货物
生产者成功送来第6号货物
生产者成功送来第7号货物
生产者成功送来第8号货物
生产者成功送来第9号货物
生产者成功送来第10号货物
生产者成功送来第11号货物
生产者成功送来第12号货物
生产者成功送来第13号货物
生产者成功送来第14号货物
生产者成功送来第15号货物
生产者成功送来第16号货物
生产者成功送来第17号货物
生产者成功送来第18号货物
生产者成功送来第19号货物
生产者成功送来第20号货物
货物已满
消费者成功取走第20号货物
消费者成功取走第19号货物
消费者成功取走第18号货物
消费者成功取走第17号货物
消费者成功取走第16号货物
消费者成功取走第15号货物
消费者成功取走第14号货物
消费者成功取走第13号货物
消费者成功取走第12号货物
消费者成功取走第11号货物
消费者成功取走第10号货物
消费者成功取走第9号货物
消费者成功取走第8号货物
消费者成功取走第7号货物
消费者成功取走第6号货物
消费者成功取走第5号货物
消费者成功取走第4号货物
消费者成功取走第3号货物
消费者成功取走第2号货物
消费者成功取走第1号货物
已缺货!!!
生产者成功送来第1号货物
生产者成功送来第2号货物
生产者成功送来第3号货物
生产者成功送来第4号货物
生产者成功送来第5号货物
生产者成功送来第6号货物
生产者成功送来第7号货物
生产者成功送来第8号货物
生产者成功送来第9号货物
生产者成功送来第10号货物
生产者成功送来第11号货物
生产者成功送来第12号货物
生产者成功送来第13号货物
生产者成功送来第14号货物
生产者成功送来第15号货物
生产者成功送来第16号货物
生产者成功送来第17号货物
生产者成功送来第18号货物
生产者成功送来第19号货物
生产者成功送来第20号货物
货物已满

例4:现在两个线程,可以操作同一个变量,实现一个线程对该变量加1,一个线程对该变量减1, 实现交替,来十轮,变量初始值为0。

1 高内聚低耦合
2 线程  操作  资源
public class ShareData {
	private int num = 0;

	// 增加数据的方法
	public synchronized void incrment() throws InterruptedException {
		// 此处应该用While不能用if:因为多个线程被唤醒进入if时会出错误,会出现虚假唤醒,while可以拉回重新判断
		while (num != 0) {
			// 等待
			this.wait();
		}
		num++;
		System.out.println(Thread.currentThread().getName() + "\t" + num);
		// 唤醒其他所有线程
		this.notifyAll();
	}

	// 减少数据的方法
	public synchronized void descment() throws InterruptedException {
		while (num == 0) {
			// 等待
			this.wait();
		}
		num--;
		System.out.println(Thread.currentThread().getName() + "\t" + num);
		this.notifyAll();
	}
}
public class MyTest {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		// 内部类如果要引用外部类的变量,则该变量必须为final,这是规定
		final ShareData sd = new ShareData();

		//线程1
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					for (int i = 0; i < 10; i++) {
						sd.incrment();
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "AA").start();

		//线程2
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					for (int i = 0; i < 10; i++) {
						sd.descment();
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "BB").start();

		//线程3
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					for (int i = 0; i < 10; i++) {
						sd.incrment();
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "CC").start();

		//线程4
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					for (int i = 0; i < 10; i++) {
						sd.descment();
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "DD").start();
	}
}

猜你喜欢

转载自blog.csdn.net/wxd_1024/article/details/80496111