Java丨生产者与消费者实现原理

一、多线程的关键点回顾

1、什么是进程
程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。而进程是程序在处理机上的- -次
执行过程,它是一个动态的概念。
进程是一个具有一定独立功能的程序,一个实体,每一个进程都有它自己的地址空间。
2、进程的状态:
进程执行时的间断性,决定了进程可能具有多种状态。事实上,运行中的进程具有以下三种基本状态。
1)就绪状态(Ready)
2)运行状态( Running)
3)阻塞状态( Blocked)
Java丨生产者与消费者实现原理_第1张图片

 

线程实现的两种方式
在Java中如果要想实现多线程的操作,有两种实现方法:

//(1) - -种是继承Thread类
class MyThread extends Thread{
public void run(){
//逻辑处理
}
}
MyThread mt = new MyThread();
mt.start();
//(2)另外一种是实现Runnable接口
class MyRunnable implements Runnable{
public void run(){
//逻辑处理
}
}
MyRunnable mr = new MyRunnable();
Thread t = new Thread(mr);
t.start();

其中第二种方法是最常用的

 

线程休眠;sleep
使用sleep方法实现,使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),释放CPU的时间片,具体取
决于系统定时器和调度程序的精度和准确性。线程不会丢失任何显示器的所有权。
 

进程与线程的区别;

进程是一个独立的应用程序,具有独立的内存空间。
线程是一个进程中的执行路径,在同一个进程中,多个线程共享-个内存空间。

Java丨生产者与消费者实现原理_第2张图片

(PS:进程是一个概念,一个应用程序由一个或多个线程来组成,从概念上就把一个应用程序当做是系统中的一个进程)

 

线程等待;wait
使用wait方法实现,让线程暂时停止执行,释放CPU的时间片,并释放对象监视器的所有权,等待其它线程通过
notify方法来唤醒。
 

多线程图解;

New(初始化状态)
Runnable(可运行/运行状态)
Blocked(阻塞状态)
Dead(终止状态)


Java丨生产者与消费者实现原理_第3张图片

 

Waiting(无时间限制的等待状态)
Timed_ Waiting(有 时间限制的等待状态)

 


二、生产者与消费者案例分析

饭店里的有一个厨师和一个服务员,这个服务员必须等待厨师准备好膳食。.
当厨师准备好时,他会通知服务员,之后服务员上菜,然后返回继续等待。
这是一个任务协作的示例,厨师代表生产者,而服务员代表消费者。

厨   师=生产者;

服务员=消费者。

Demo;
 

public class ProducterConsumerDemo {
    public static void main(String[] args) {
        Food food = new Food();
        Producter p = new Producter(food);
        Consumer c = new Consumer(food);
        Thread pt = new Thread(p);
        Thread ct = new Thread(c);
        pt.start();
        ct.start();
    }
}

/**
 * 生产者
 */
class Producter implements Runnable{
    private Food food;
    public Producter(Food food){
        this.food = food;
    }
    @Override
    public void run() {
        //模拟生产者不断的生产食物
        //一共生产30份菜,交替生产两种菜
        for (int i=0;i<30;i++){
            if(i%2==0){
                food.set("大盘鸡","分量大,吃得饱");
            }else{
                food.set("韭菜炒鸡蛋","大补,鑫鑫最爱");
            }
        }
    }
}

/**
 * 消费者
 */
class Consumer implements Runnable{
    private Food food;
    public Consumer(Food food){
        this.food = food;
    }
    @Override
    public void run() {
        //消费30份食物
        for (int i=0;i<30;i++){
            food.get();
        }
    }
}


//食物类
class Food{
    private String name;  //食物名
    private String desc; //食物描述
    private boolean flag = true; //true 表示可以生产,不能消费,false 表示可以消费,不能生产
    //Object obj = new Object();// 只是作为锁来用
    /**
     * 存值(生产产品)
     * @param name
     * @param desc
     */
    public void set(String name,String desc){
        synchronized (this) { //在对象上上锁
            if(flag==false){ //表示不能生产,所以就让出 CPU,并释放对象锁
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //表示正在生产
            this.name = name;
            try {
                //模拟生产食物的时间过程
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.desc = desc;
            flag = false;
            this.notify(); //唤醒在此对象锁上的任意一个线程
        }
    }

    /**
     * 取值(消费产品)
     */
    public void get(){
        synchronized (this) {
            if(flag==true){  //表示不能消费
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //正在消费
            System.out.println(this.name + "--" + this.desc);
            flag = true;
            this.notify(); //唤醒在此对象锁上的任意一个线程
        }
    }

    public Food() {
    }

    public Food(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}

PS:

当多个线程共享同一个数据,会出现线程安全问题

 JAVA 的多线程是使用抢占式来实现

 

 对象锁:JAVA 在设计时把锁的概念定义在对象身上,而不是线程

 生产者与消费者是 互斥关系
 对象设置锁,就是线程开发中的同步
 在此示例中,我们需要达到的效果是:两个线程在各自调用同一个 Food对象的不同方法时,
 要限制两个方法以互斥的方式进行,比如,A 线程调用了set方法,那么 B 线程必须等待 A 线程完成set方法的调用后
 才能执行,相反是一样的。

 应用场景:一个是负责提供数据的线程,把数据拿到后放到队列中,另一个线程不断的从队列中取出数据进行操作


遗留问题:

1、生产者消费者模型的作用是什么
2、sleep方 法和wait方法有什么区别
3、如何在两个线程之间共享数据
4、为什么wait()方法和notify()/notifyAl()方法要在同步块中被调用
5、wait()方法和notify()/notifAIl()方法在放弃对象监视器时有什么区别.
6、Thread.sleep(0)的作用是什么
 


 

你可能感兴趣的:(Java)