黑马程序员_2_多线程之生产者与消费者
------- android培训、java培训、期待与您交流! ----------
多线程通讯问题解析:
我们要了解生产者与消费者问题,首先要明白,多线程执行的流程即生命周期。
文字如下:
调用了sleep、wait方法的时候
<----------临时阻塞<----------
调用start方法 抢到了cpu的执行权 执行完毕任务
创建--------------> 可运行状态 ----------------->运行状态-------------->死亡
<----------------
被抢夺了cpu的执行权
图列如下:
线程通讯:一个线程完成自己的任务后告诉另一个线程执行他自己的任务。
下面我们来看看线程通讯问题实例-----生产者与消费者:
首先描述一个产品类。
package cn.chen.runndom;
//描述一个产品类。
class Product {
String name;//产品名
double price;//产品价格
boolean flag =false;//是否生产完标记,默认为false表示没有生产完,true已经生产完毕了。
//无参的构造方法。
public Product() {}
public Product(String name, double price) {
this.name = name;
this.price = price;
}
}
然后描述一个生产者。
package cn.chen.runndom;
//描述一个生产者
class Producer extends Thread{
//在生产者类中维护一个产品
Product p;
//通过构造函数传递产品进来,保证与消费者是同一一个产品对象。
public Producer(Product p) {
this.p = p;
}
//多线程执行的代码。
public void run(){
int i = 0;//定义变量
while(true){
//同步代码块。
synchronized (p) {
if(!p.flag){
if(i%2==0){
p.name="苹果";
p.price=5.5;
}else{
p.name="香蕉";
p.price=1.5;
}
System.out.println("生产者已经生产了"+p.name+"价格是:"+p.price);
//改变标记。让生产者先停止,等待消费完
p.flag=true;
//唤醒线程池中正在等待的线程
p.notify();
i++;
}else{
try {
//线程进入线程池中等待被唤醒
p.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
描述一个消费者:
package cn.chen.runndom;
class Customer extends Thread{
//消费者类维护了一个产品类
Product p;
//通过构造函数传递产品,保证与生产者是同一个产品对象
public Customer(Product p) {
this.p = p;
}
//消费者线程执行的任务
public void run(){
//线程同步代码块,解决价格错乱问题。
synchronized (p) {
while(true){
if(p.flag){
System.out.println("消费者消费了"+p.name+"价格是:"+p.price);
p.flag=false;
//唤醒线程池中等待的线程
p.notify();
}else{
try {
p.wait();//线程进入线程池等待被唤醒。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
现在万事俱备,创建线程并开启。
package cn.chen.runndom;
public class mainTest {
public static void main(String[] args) {
//创建产品对象。
Product product = new Product();
//创建生产者线程对象。把产品对象通过构造方法传递
Producer producer = new Producer(product);
//创建消费者线程对象、把产品对象通过构造方法传递
Customer customer = new Customer(product);
//调用start方法开启线程。
producer.start();
customer.start();
}
}
输出结果。
从输出结果可以看出,生产者每生产完一个产品,消费者就会消费一个产品。
线程通讯中:
wait();线程等待,如果一个线程调用了该方法,那么该方法就会进入等待状态,必须要其他线程唤醒,才能重新进入可运行状态。
notily();唤醒等待线程中的一个线程。
注意:这俩个方法都是上帝Object类中的方法。必须在同步代码块或者同步函数中调用。且
必须使用锁对象调用。
一个线程执行了wait方法的时候,那么该线程会进入一个以锁对象为标识符的一个线程池等待。
一个线程执行了notify方法的时候,会唤醒线程池中等待线程的其中一个线程,
注意:执行wait方法的时候是会释放锁对象,
线程执行sleep方法的时候不会释放锁对象。所以要使用wait方法。