1.线程通信
在前面的章节对synchronized的用法做了介绍。它可以解决多线程对公共资源的利用问题。但是不同线程之间,有时候需要协作,以提高工作效率,因此需要相互通信。下面介绍在synchronized中两个方法:wait和notify方法
2.wait 和notify
1.wait 方法表示线程一直等待,直到其他线程通知。与sleep不同的是,wait会释放资源。
2.notify唤醒一个处于等待状态的线程
3.notifyAll。唤醒同一个对象上所有调用wait方法的线程。
注意:上面的方法均是Object类的方法,都只能在同步方法或同步代码块中使用,否则会抛出异常。
3. 使用管程法解决消费生产者问题。
生产消费者问题:指的是,在一一些场景下,有线程等待,并通知其他消费者对资源进行消费。资源充足的时候,可以消费,不足的时候通知生产者生产。已达到一个供需稳定的系统。
下面以生产炸鸡和吃炸鸡作为例子:
package Pool;
//生产者、消费者模式
public class PCModel {
public static void main(String args[]) {
SynContainer container=new SynContainer();
new Producer(container).start();
new Customer(container).start();
}
}
//生产者
class Producer extends Thread{
SynContainer container;
public Producer(SynContainer container) {
this.container=container;
}
public void run() {
for (int i = 1; i <= 100; i++) {
container.push(new Chicken(i));
System.out.println("生产者生产第"+i+"鸡肉");
}
}
}
//消费者
class Customer extends Thread{
//消费者负责吃鸡
SynContainer container;
public Customer(SynContainer container) {
this.container=container;
}
public void run() {
for (int i = 1; i <=100; i++) {
System.out.println("消费者消费第"+container.pop().id+"鸡肉");
}
}
}
//炸鸡
class Chicken{
public int id;
public Chicken(int id) {
this.id=id;
}
}
//容器
class SynContainer{
//容器负责消费者消费和生产者生产
Chicken[] chickens=new Chicken[10];
public int count=0;
public synchronized void push(Chicken chicken) {
if(count==chickens.length) {
//通知生产者停止,消费者消费
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
chickens[count]=chicken;
count++;
this.notifyAll();
}
public synchronized Chicken pop() {
if(count==0) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
count--;
Chicken chicken=chickens[count];
this.notifyAll();
return chicken;
}
}
消费只负责吃鸡,生产者负责生产鸡块。最核心的代码在SynContainer类中,我们定义了push和pop方法,分别表示生产者往容器放鸡块和消费者取餐。
我们定义容器的大小为10.
1.在push方法中,如果count增加到和容器的大小一致,说明容器已经满了,这个时候,如果再生产,容器就放不小了。就需要调用调用wait方法,通知使用对应的线程等待。其中使用this.wait方法实现。这个this是指向了Producer 实例。之后,调用notify方法,唤醒处于等待“开吃的”消费们。
2.在“pop”方法中,我们进行数据判断,如果count==0,说明没有鸡块可以吃,就进行等待,然后唤醒生产者要炸鸡块了。如此相互协作。
下面是运行结果:
生产者最大可以连续生产10次,就停止,然后通知消费者消费。中间也可能出现生产一只,消费一只的情况。