1、线程的通信方式通信:
其实就是多个线程在操作同一个资源,但是操作的动作不同。
2、API介绍
Object.wait():在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
Object.notify():唤醒在此对象监视器上等待的单个线程。
Object.notifyAll():唤醒在此对象监视器上等待的所有线程。
先来实现一个需求:
有两个线程,一个往资源池中生产数据,一个从资源池中消费数据
代码如下:
class Res {
private String name;
private String sex;
private boolean flag = false; //用来判断有没有数据
/**
* 生产一条数据
* @param name
* @param sex
*/
public synchronized void set(String name, String sex) {
if (flag)
try {this.wait();} catch (Exception e) {}
this.name = name;
this.sex = sex;
flag = true;
this.notify(); //唤醒另一个线程
}
/**
* 消费数据
*/
public synchronized void out() {
if (!flag)
try {this.wait();} catch (Exception e) {}
System.out.println(name + "........" + sex);
flag = false;
this.notify();
}
}
class Input implements Runnable {
private Res r;
Input(Res r) {
this.r = r;
}
public void run() {
int x = 0;
while (true) {
if (x == 0)
r.set("mike", "man");
else
r.set("丽丽", "女女女女女");
x = (x + 1) % 2;
}
}
}
class Output implements Runnable {
private Res r;
Output(Res r) {
this.r = r;
}
public void run() {
while (true) {
r.out();
}
}
}
class InputOutputDemo2 {
public static void main(String[] args) {
Res r = new Res();
new Thread(new Input(r)).start();
new Thread(new Output(r)).start();
}
}
上面再生产和消费都是单线程的情况下是没有问题的,但是如果变成了两个生产者和两个消费者,且该资源池只能存放一条数据,那么上面代码就需要修改了。
第一点:需要将上面代码的 notify() 改成 notifyAll()。因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。
第二点:需要将
if (flag)
try {this.wait();} catch (Exception e) {}
改成:
while(flag)
try {this.wait();} catch (Exception e) {}
原因:让被唤醒的线程再一次判断标记。
多线程版本的完整代码如下:
class ProducerConsumerDemo {
public static void main(String[] args) {
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r);
new Thread(pro).start();
new Thread(pro).start();
new Thread(con).start();
new Thread(con).start();
}
}
class Resource {
private String name;
private int count = 1;
private boolean flag = false;
// t1 t2
public synchronized void set(String name) {
while (flag)
try {this.wait();} catch (Exception e) {}// t1(放弃资格) t2(获取资格)
this.name = name + "--" + count++;
System.out.println(Thread.currentThread().getName() + "...生产者.." + this.name);
flag = true;
this.notifyAll();
}
// t3 t4
public synchronized void out() {
while (!flag)
try {wait();} catch (Exception e) {}// t3(放弃资格) t4(放弃资格)
System.out.println(Thread.currentThread().getName() + "...消费者........." + this.name);
flag = false;
this.notifyAll();
}
}
class Producer implements Runnable {
private Resource res;
Producer(Resource res) {
this.res = res;
}
public void run() {
while (true) {
res.set("+商品+");
}
}
}
class Consumer implements Runnable {
private Resource res;
Consumer(Resource res) {
this.res = res;
}
public void run() {
while (true) {
res.out();
}
}
}