都说线程间的通信是使用wait和notify或notifyAll进行通信。这点不用怀疑,大家都很清楚,可是用代码实现怎么简单的处理?下面我举个简单的生产者消费者模型,虽然可以用队列,但是此处只是为了说明线程间的wait和notify原理。
1.首先定定义一个产品
/**
* 商品
* 模拟线程间的通信
* 对象的锁:
* 锁池(synchronized)
* 等待池(wait notify notifyAll)
*
* @author houxiurong
* @date 2019-10-05
*/
public class Product {
private String brand;
private String name;
//..... 省略 getter/setter
//信号灯的功能 如果有商品 消费者才消费 否则生产者生产
//默认没有商品 要生产者生成
private boolean flag = false;
public synchronized void setProduct(String brand, String name) {
//flag==true
//如果有商品,则生产者线程等待一会
if (flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.setBrand(brand);
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setName(name);
//生产结束 信号标记为true
System.out.println("生产者生产了" + this.getBrand() + "----" + this.getName());
flag = true;
//有商品了,通知其他线程开始作业
notify();
}
public synchronized void getProduct() {
//如果没有商品 则消费者线程等待
//flag==false
if (!flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//有商品,开始消费
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者消费了" + this.getBrand() + "==" + this.getName());
//消费结束 通知消费者
flag = false;
notify();
}
}
2.定义一个生产者-实现Runnable方法使其具有多线程能力
/**
* 生产者生产商品
*
* @author houxiurong
* @date 2019-10-05
*/
public class Producer implements Runnable {
private Product product;
public Producer(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 1; i <= 10; i++) {//模拟生成10个商品
if (i % 2 == 0) {
product.setProduct("Dove", "Chocolate");
} else {
product.setProduct("兰州黄河", "啤酒");
}
}
}
}
3.定义一个消费者-实现Runnable方法使其具有多线程能力
/**
* 消费者消费商品
*
* @author houxiurong
* @date 2019-10-05
*/
public class Consumer implements Runnable {
private Product product;
public Consumer(Product product) {
this.product = product;
}
@Override
public void run() {
//模拟消费10个商品
for (int i = 1; i <= 10; i++) {
product.getProduct();
}
}
}
4.开始测试
/***
* +--> [信号灯] <---+
* | |
* | |
* [生产者] [消费者]
* | |
* | |
* +---> [商品] <---+
*/
public static void main(String[] args) {
//定义一个商品
Product product = new Product();
//生产者
Producer producer = new Producer(product);
//消费者
Consumer consumer = new Consumer(product);
//这里使用了静态代理设计模式, Thread相当于代理着
new Thread(producer).start();
new Thread(consumer).start();
}
总结:
在Java对象中有两种池:
锁池:一般理解为synchronized。
等待池:一般理解为wait,notify/notifyAll--必须在synchronize中才能使用,不然会抛出异常:
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
.....
1.如果线程调用了某个对象的wait方法,那么该线程进入到该对象的等待池中(并且将其获得的释放掉当前持有的锁);
2.如果未来的某一刻,另外一个线程调用了相同对象的notify方法或者notifyAll方法,那么该等待池中的线程就会被唤起,然后进入到对象的锁池里面去获得该对象的锁。
3.如果获的锁成功,那么该线程就会沿着wait方法之后的路径继续执行。(注意是沿着wait方法的之后的路径)