线程的通信:不同的线程执行不同的任务,如果这些任务有某种关系,线程之间必须能够通信,协调完成工作
经典的生产者和消费者的案例(producer/Consumer)
分析案例:
(1)生产者和消费者应该操作共享的资源(实现方式来做)
(2)使用一个或多个线程来表示生产者
(3)使用一个或多个线程来表示消费者
为什么生产者不直接把数据给消费者,而是先把数据存储到共享中,然后在从共享资源中取出数据,在消费
这里体现了面向对象的设计理念:低耦合
高(紧)耦合:直接使用生产者吧肉包子给消费者,那么生产者中得存在消费者的引用,同理,消费者要消费生产者生产的肉包子,消费者中也得存在生产者对象的应用
低(松)耦合: 使用一个中间对象,屏蔽了生产者和消费者的直接的数据交互,例子:主板和独立显卡
//表示共享资源
public class SharedResource {
private String name = null;
private Integer age;
private boolean isEmpty = true;
/**
* 用于生产者向共享资源中存储数据
*
*/
synchronized public void push(String name, Integer age) {
try {
while (!isEmpty) {
this.wait();// 使用同步锁对象来调用,表示当前线程释放同步锁,进入等待池,只能其他线程调用
}
// ---开始生产过程---
Thread.sleep(1000);
this.name = name;
this.age = age;
// ----生产过程完毕---
isEmpty = false;
this.notifyAll();//唤醒另一个线程
} catch (Exception e) {
e.printStackTrace();
}
}
// 用于消费者从共享资源中取出数据
synchronized public void popup() {
try {
while (isEmpty) { // while 比if 更安全
this.wait();// 使用同步锁对象来调用,表示当前线程释放同步锁,进入等待池,只能其他线程调用
}
// ---开始消费过程---
Thread.sleep(1000);
System.out.println(this.name + "-" + this.age);
// ---消费过程完毕---
isEmpty = true;
this.notifyAll();//唤醒另一个线程
} catch (Exception e) {
e.printStackTrace();
}
}
}
//消费者
public class Producer implements Runnable {
private SharedResource resource = null;
public Producer(SharedResource resource) {
this.resource = resource;
}
public void run() {
for (int i = 0; i < 50; i++) {
if (i % 2 == 0) {
resource.push("allen", 19);
} else {
resource.push("mew", 20);
}
}
}
}
//消费者
public class Consumer implements Runnable {
private SharedResource resource = null;
public Consumer(SharedResource resource) {
this.resource = resource;
}
public void run() {
for (int i = 0; i < 50; i++) {
resource.popup();
}
}
}
----------------------------------------------------------------------------------------------
同步锁池:
同步锁必须选择多个线程共同的资源对象
当前生产者在生产数据的时候(先拥有同步锁),其他线程就在锁池中等待获取锁,
当线程执行完同步代码块的时候,就会释放同步锁,其他线程开始抢锁的使用权
等待和唤醒机制
------------------------------------------------------------------------------------------------------------------
Java.lang.Object类提供两类用于操作线程通信的方法: