JAVA-16.2-生产消费者模式

线程间通信(生产消费者问题):不同类型线程针对同一个资源的操作
  举例:1.系统不仅要卖票还要入票
     2.不仅要卖肉夹馍还要生产肉夹馍
这里写图片描述
今天主要讲解单生产单消费模式。
  如果我们现在利用单生产单消费模式对学生进行设置姓名年龄,获取学生姓名年龄该怎么办呢?
这里写图片描述
首先,线程间通讯:
  资源:Student(将学生作为资源进行操作)
  设置数据线程:SetThread
  获取数据线程:GetThread
  测试类:StudentDemo
先考虑几个问题:
1.怎么保证资源唯一?(让设置和获取到的是同一资源,否则获取到的只能是null,0)
  解决方法:当在不同的类中,需要使用同一个数据的时候,可以考虑将数据利用构造方法进行传参
2.数据重复问题?数据错乱问题?
  解决方法:同步代码块或者同步方法都可以解决数据问题,加锁。
    ①设置线程和获取线程需要全部做一个限制,相当与两个线程都需要加锁
    ②设直线程和获取线程,加的锁必须是同一个,才可以保证数据安全

package com.edu_04;
//Student类
public class Student {
    String name;
    int age;
}
package com.edu_04;
//设置线程
public class SetThread implements Runnable{

    private Student s;
    private int x=0;

    public SetThread(Student s){
        this.s = s;
    }

    @Override
    public void run() {
        //给学生对象设置姓名和年龄
        //Student s = new Student();
        while (true) {
            synchronized (s) {
                if (x%2==0) {
                    s.name = "张三";
                    s.age = 50;
                }else {
                    s.name = "李四";
                    s.age = 35;
                }
                x++;
            }   
        }   
    }
}
package com.edu_04;
//获取线程
public class GetThread implements Runnable{
    private Student s;

    public GetThread(Student s){
        this.s = s;
    }
    @Override
    public void run() {
        //获取线程,获取学生对象的姓名和年龄
        //Student s = new Student();
        while (true) {
            synchronized (s) {  
                System.out.println(s.name+"--"+s.age);  
            }
        }
    }
}
package com.edu_04;
//测试类
public class StudentDemo {
    public static void main(String[] args) {
        //创建一个学生对象
        Student s = new Student();

        //创建设置和获取线程,并开启线程
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);

        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);

        //开启线程
        t1.start();
        t2.start();
    }
}

  这样一来虽然保证了数据的安全性,资源唯一性,但是并没有实现礼让效果。怎么让数据变得和谐礼让呢?也就是说生产一个,获取一个,有理有序?
  解决方法:使用等待唤醒机制改进,实现礼让效果
将上述问题全部解决之后,就得到了单生产单消费模式的整个流程,代码如下:
方式一:利用同步代码块

package com.edu_05;
//学生类
public class Student {
    String name;
    int age;
    boolean flag;//在这里可以作为对象的一个标记,如果是false说明该对象没有数据,如果是true说明该对象有数据
}
package com.edu_05;
//设置线程
public class SetThread implements Runnable{
    private Student s;
    private int x = 0;

    public SetThread(Student s){
        this.s = s;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (s) {
                //判断该对象此时有没有数据
                if (s.flag) {
                    //等待
                    try {
                        s.wait();//设置线程等待,释放锁s
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

                if (x%2==0) {
                    s.name = "张三";
                    s.age = 50;
                }else {
                    s.name = "李四";
                    s.age = 35;
                }
                x++;//x=1

                //此时对象有数据了
                s.flag = true;
                s.notify();//如果有等待的线程就唤醒,如果没有等待的线程,则没有任何效果
            }//在此时释放锁对象s
        }
    }
}
package com.edu_05;
//获取线程
public class GetThread implements Runnable{
    private Student s;

    public GetThread(Student s){
        this.s = s;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (s) {
                //判断对象有没有数据
                if (!s.flag) {
                    //等待设置线程给对象设置数据
                    try {
                        s.wait();//获取线程处于等待状态,释放锁对象s,在哪里跌倒在哪里爬起来
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

                System.out.println(s.name+"--"+s.age);//张三--50
                                                      //李四--35
                                                      //张三--50

                //当获取线程从学生对象中获取了数据之后,我们就默认他已经没有数据了,此时我们应该
                //继续让设置线程继续给学生对象设置信息
                s.flag = false; 
                s.notify();
            }
        }
    }
}
package com.edu_05;
//测试
public class StudentDemo {
    public static void main(String[] args) {
        //创建学生对象
        Student s = new Student();
        //创建设置线程和获取线程
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);

        //开启线程
        t1.start();
        t2.start();
    }
}
//张三--50
//李四--35
//张三--50

方式二:利用同步方法

package com.edu_06;
//学生类,并将设置获取方法封装
public class Student {
    //块编辑(alt+shift+a):在使用块编辑的时候,一定要将输入法切换到英文输入法,不然会出问题
    private String name;
    private int age;
    private boolean flag;//在这里可以作为对象的一个标记,如果是false说明该对象没有数据,如果是true说明该对象有数据

    //提供公共的方法设置信息
    public synchronized void setInfo(String name,int age){
        if (this.flag) {
            //等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        //没有值的话,在这里给对对象设置数据
        this.name = name;
        this.age = age;

        //更改标记,唤醒获取线程获取数据
        this.flag = true;
        this.notify();

    }
    //提供公共的方法获取信息
    public synchronized void getInfo(){
        if (!this.flag) {
            //没有值
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        //有数据,取数据
        System.out.println(this.name+"--"+this.age);

        //取完数据之后,就没有数据了
        this.flag = false;
        this.notify();
    }
}
package com.edu_06;
//设置线程
public class SetThread implements Runnable{
    private Student s;
    private int x = 0;

    public SetThread(Student s){
        this.s = s;
    }
    @Override
    public void run() {
        while (true) {
                if (x%2==0) {
                    s.setInfo("张三", 50);
                }else {
                    s.setInfo("李四", 35);
                }
                x++;//x=1
            }
    }
}
package com.edu_06;
//获取线程
public class GetThread implements Runnable{
    private Student s;

    public GetThread(Student s){
        this.s = s;
    }

    @Override
    public void run() {
        while (true) {
            s.getInfo();
        }
    }
}
package com.edu_06;
//测试
public class StudentDemo {
    public static void main(String[] args) {
        //创建学生对象
        Student s = new Student();
        //创建设置线程和获取线程
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);

        //开启线程
        t1.start();
        t2.start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值