包子案例
多个类(称为线程一类,线程二类) 需要一个共有的变量,即将这个变量封装为一个类(称为属性类)的属性,注意属性类的属性修饰符为public公共的,在测试类中new 这个属性类实例化为对象,然后将此对象作为参数传入需要的多个类(线程一,线程二)中,就可以实现共享对象的属性即变量,且多个类(线程一,线程二) 需要定义此对象(属性类)为私有变量,并提供有参构造
生产者线程和消费者线程要有共享对象,即将包子提升为类作为参数传入生产者线程和消费者线程,这个包子类就是共享的对象,就可以使用 synchronized(包子类) 锁住共享对象包子,就不会发生多线程的通信问题,多个生产者和消费者也是这个原理只是共享对象变成队列而已
线程就是一个普通的类,可以随便写,只是继承Thread类,必须要重写run()方法,当然不重写runf方法就不是多线程了,起不到线程的作用。线程实现方式第一种方式是继承extends Thread 第二种是实现Implements Runnable 接口 第三种 是实现 Implements Callable接口,其中第二种方式 多线程自动共享数据 ,第三种方式带返回值 三种方式实现线程的子类都是普通的类,只是多了一个重写方法
代码
要点:生产者线程增加包子属性,有参构造方法。重写run方法里的线程的while的条件表达式,if(包子的状态存在) {需要等待} 包子不存在就生产包子,或做其他一系列要做的事,然后将包子状态改变,唤醒其他线程
消费者线程增加包子属性,有参构造方法。重写run方法里的线程的while的条件表达式,if(包子的状态不存在) {需要等待} 包子存在就消费包子,或做其他一系列要做的事,然后将包子状态改变,包子数量++(为什么只在消费者线程有着语句,因为生产一个包子再消费一个包子才算一轮)唤醒其他线程
看了后面,重写run方法里的线程的while的条件表达式(建议直接为true,后面再多写个if(条件){break}跳出循环)
包子类
要点:共享的数据类,可以写任何想要的数据
package day22;
public class BaoZi {
public String pi;
public String xian;
//定义一个标记表示是否存在包子 false 没有包子 ture 有包子
boolean flag = false;
//boolean 默认值为false
int count=1;
}
生产者类
package day22;
public class ProducterThread extends Thread{
private BaoZi baoZi;
public ProducterThread(BaoZi baoZi){
this.baoZi = baoZi;
}
@Override
public void run() {
//一直生产包子
while (baoZi.count<10){
//同步代码块 //互斥锁
synchronized(baoZi){
//已存在包子 等待消费 不需要在生产
if(baoZi.flag){
try {
baoZi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//不存在包子 开始生产包子
baoZi.pi = "薄皮";
baoZi.xian ="韭菜鸡蛋";
System.out.println("==============");
//System.out.println("我生产了一个"+baoZi.pi+baoZi.xian+"的包子");
System.out.println("我生产了第"+baoZi.count+"个"+baoZi.pi+baoZi.xian+"的包子");
//将标记值设置为ture
baoZi.flag = true;
//通知消费者去消费
baoZi.notify();
}
}
}
}
消费者类
package day22;
public class CustomerThread extends Thread{
private BaoZi baoZi;
public CustomerThread(BaoZi baoZi){
this.baoZi=baoZi;
}
@Override
public void run() {
while (baoZi.count<=10){
synchronized (baoZi){
//如果包子不存在 等包子生成出来
//可以将!baoZi.flag 换成 baoZi.flag == false 就好理解了
if(!baoZi.flag){
//无线等待
try {
baoZi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//包子存在 吃包子
//System.out.println("我消费了一个"+baoZi.pi+baoZi.xian+"的包子");
System.out.println("我消费了第"+baoZi.count+"个"+baoZi.pi+baoZi.xian+"的包子");
baoZi.count++;
baoZi.pi=null;
baoZi.xian=null;
//标记设置为false
baoZi.flag = false;
//通知生产者开始生产
baoZi.notify();
}
}
}
}
测试类
package day22;
public class Test05 {
public static void main(String[] args) {
BaoZi baoZi =new BaoZi();
//开启生产者的线程
new ProducterThread(baoZi).start();
//开启消费者的线程
new CustomerThread(baoZi).start();
}
}
原文地址
package threadsDemo;
import java.util.ArrayList;
import java.util.Random;
public class BreadShop {
// 装包子的盘子
public ArrayList<Bread> breadList = new ArrayList<Bread>();
// 包子的种类:肉包和菜包
public BreadType [] breadTypes = { BreadType.MEAT, BreadType.VEGETABLES };
// 已经出炉的包子总数
public int totalCount = 0;
// 点的包子数
public final int MAX_COUNT = 20;
enum BreadType{
MEAT,VEGETABLES
}
class Bread {
public BreadType type;
public Bread(BreadType type){
this.type=type;
}
}
class Product implements Runnable {
/*private boolean isWork = false;
public Product() {
this.isWork = true;
}*/
// 把包子蒸熟后放到盘子里
public void makeBread(Bread bread) {
breadList.add(bread);
switch(bread.type)
{
case MEAT:
System.out.println("老板生产了一个肉包");
break;
case VEGETABLES:
System.out.println("老板生产了一个菜包");
break;
default:
break;
}
}
@Override
public void run() {
while(true/*isWork*/)
{
try {
synchronized(breadList)
{
// 他们还没吃完,继续等待
if(breadList.size() > 0) {
breadList.wait();
}
// 一次蒸10个包子
for(int i = 0; i < 10; ++ i)
{
int type = new Random().nextInt(2);
Bread bread = new Bread(breadTypes[type]);
this.makeBread(bread);
}
totalCount += 10;
// 通知他们可以吃包子了
breadList.notifyAll();
}
// 做完了20个包子
if(totalCount >= MAX_COUNT)
{
//isWork = false;
break;
}
}catch(Exception e) {
e.printStackTrace();
//isWork = false;
}
}
}
}
class Consumer implements Runnable
{
private int id;
public Consumer(int id)
{
this.id = id;
}
// 吃包子
public void eat(Bread bread)
{
BreadType type = bread.type;
switch (type) {
case MEAT:
System.out.println(id + "号消费者" + "吃了一个肉包");
break;
case VEGETABLES:
System.out.println(id + "号消费者" + "吃了一个菜包");
break;
default:
break;
}
}
@Override
public void run() {
while(true)
{
try{
synchronized(breadList)
{
// 包子还没做好
if(breadList.size() == 0)
{
// 吃完了所有包子
if(totalCount >= MAX_COUNT) {
break;
}
// 通知老板娘赶快做包子
breadList.notifyAll();
// 等老板娘做包子
breadList.wait();
}
else
{
// 从盘子里拿包子吃
Bread bread = breadList.remove(0);
this.eat(bread);
}
}
// 这里模拟吃包子的时间,也可以增大其他线程获得锁的概率,提高公平性
Thread.sleep(100);
}catch(Exception e)
{
e.printStackTrace();
//break;
}
}
}
}
public static void main(String[] args) {
BreadShop bs = new BreadShop();
//内部类的实例化 先实例化外部类 再 内部类 对象名 = 外部类对象名.new 内部类
//最原始的是 实例化静态内部类对象的模板是: 外部类类名.内部类类名 xxx = new 外部类类名.内部类类名()
//实例化非静态内部类对象的模板是:外部类类名.内部类类名 xxx = 外部类对象名.new 内部类类名()
//BreadShop.Consumer consumer =bs.new Consumer(1);
// 5个coder来到包子店点包子
for(int i = 1; i < 6; ++ i)
{
Thread t = new Thread(bs.new Consumer(i));
t.start();
}
// 老板娘开始做包子
Thread productThread = new Thread(bs.new Product());
//productThread.setPriority(Thread.MAX_PRIORITY);
productThread.start();
}
}
内部类的实例化 先实例化外部类 再 内部类 对象名 = 外部类对象名.new 内部类
最原始的是
实例化静态内部类对象的模板是: 外部类类名.内部类类名 xxx = new 外部类类名.内部类类名()
实例化非静态内部类对象的模板是:外部类类名.内部类类名 xxx = 外部类对象名.new 内部类类名()
BreadShop.Consumer consumer =bs.new Consumer(1);
共享数据类
package ThreadsDemo1;
import java.util.ArrayList;
import java.util.List;
public class BaoZiDate {
public List<BaoZi> baoZiList = new ArrayList<>();
public BaoZiType[] baoZiTypes = {BaoZiType.MEAT, BaoZiType.VEGETABLES, BaoZiType.XIAO};
//最多包子数,只卖20个 ,一个集合10个,生产10个再卖
public final int MAX_COUNT = 20;
//已经卖了的包子数
public int totalCount=0;
enum BaoZiType {
MEAT,VEGETABLES,XIAO;
}
class BaoZi {
public BaoZiType baoZiType;
public BaoZi(BaoZiType baoZiType) {
this.baoZiType = baoZiType;
}
}
}
生产者类
package ThreadsDemo1;
import java.util.Random;
public class Product extends Thread{
private BaoZiDate shareDate;
public Product(BaoZiDate shareDate) {
this.shareDate = shareDate;
}
@Override
public void run() {
while (true){
synchronized (shareDate){
//包子集合有包子
if(shareDate.baoZiList.size()>0){
try {
shareDate.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//包子集合没有包子,生产包子
for (int i = 0; i < 10; i++) {
int type =new Random().nextInt(3);
//作用等同于 int type = (int)(Math.random()*4); 但是Math.random()在多线程中不安全
BaoZiDate.BaoZi baoZi = shareDate.new BaoZi(shareDate.baoZiTypes[type]);
shareDate.baoZiList.add(baoZi);
switch(baoZi.baoZiType)
{
case MEAT:
System.out.println("老板生产了一个肉包");
break;
case VEGETABLES:
System.out.println("老板生产了一个菜包");
break;
case XIAO:
System.out.println("老板生产了一份小笼包");
break;
default:
break;
}
}
shareDate.totalCount += 10;
shareDate.notifyAll();
}
if(shareDate.totalCount>= shareDate.MAX_COUNT){
break;
}
}
}
}
消费者类
通知生产者做包子
shareDate.notifyAll();
等生产者做包子
shareDate.wait();
因为条件是包子集合为0,没有包子在唤醒生产者,生产者就会生产10个包子,这样就会生产者生产10个包子后,消费者再吃这10个包子,吃完生产者在生产10个,有顺序的完成一轮,如果放在吃了一个包子后就唤醒,则会生产者生产10个包子,消费者1吃了一个包子,通知生产者再生产10个,然后19个包子由随机消费者消费
shareDate.notifyAll(); 换成 shareDate.notify(); 实测无区别,因为wait() 是 处于等待阻塞状态 且只有一个生产者在wait() 而另外四个消费者线程是可运行状态即就绪状态
package ThreadsDemo1;
public class Consumer extends Thread{
private BaoZiDate shareDate;
private int id;
public Consumer(BaoZiDate shareDate, int id) {
this.shareDate = shareDate;
this.id = id;
}
@Override
public void run() {
while (true){
try {
synchronized (shareDate){
if(shareDate.baoZiList.size()==0){
if(shareDate.totalCount>= shareDate.MAX_COUNT){
break;
}
// 通知生产者做包子
shareDate.notifyAll();
// 等生产者做包子
shareDate.wait();
}
else {
//从包子集合里 获取包子吃
BaoZiDate.BaoZi baoZi = shareDate.baoZiList.remove(0);
switch(baoZi.baoZiType)
{
case MEAT:
System.out.println("消费者" + id + "吃了一个肉包");
break;
case VEGETABLES:
System.out.println("消费者" + id + "吃了一个菜包");
break;
case XIAO:
System.out.println("消费者" + id +"吃了一份小笼包");
break;
default:
break;
}
}
}
// 这里模拟吃包子的时间,也可以增大其他线程获得锁的概率,提高公平性
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试类
package ThreadsDemo1;
public class Test {
public static void main(String[] args) {
BaoZiDate baoZiDate = new BaoZiDate();
Thread th1 = new Product(baoZiDate);
th1.start();
for (int i = 0; i < 5; i++) {
new Consumer(baoZiDate,i).start();
}
}
}
虽然实现了多生产者多消费者,但是没有实现 多生产者先生产10个,在多消费者吃10个,吃完再通知多生产者生产10个的 顺序
共享数据类和消费者类 同上面一样
消费者
package ThreadsDemo1;
import java.util.Random;
public class Products extends Thread{
private BaoZiDate shareDate;
private int id;
public Products(BaoZiDate shareDate,int id) {
this.shareDate = shareDate;
this.id=id;
}
@Override
public void run() {
while (true){
synchronized (shareDate){
//包子集合有包子
if(shareDate.baoZiList.size()==10){
shareDate.notifyAll();
try {
shareDate.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//包子集合没满,继续生产包子
int type = new Random().nextInt(3);
//作用等同于 int type = (int)(Math.random()*4); 但是Math.random()在多线程中不安全
BaoZiDate.BaoZi baoZi = shareDate.new BaoZi(shareDate.baoZiTypes[type]);
shareDate.baoZiList.add(baoZi);
switch (baoZi.baoZiType) {
case MEAT:
System.out.println(id + "号生产者生产了一个肉包");
break;
case VEGETABLES:
System.out.println(id + "号生产者生产了一个菜包");
break;
case XIAO:
System.out.println(id + "号生产者生产了一份小笼包");
break;
default:
break;
}
shareDate.totalCount++;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
//shareDate.notifyAll();
//shareDate.notify();
}
if(shareDate.totalCount>= shareDate.MAX_COUNT){
break;
}
}
}
}
测试类
package ThreadsDemo1;
public class Test02 {
public static void main(String[] args) {
BaoZiDate baoZiDate = new BaoZiDate();
for (int i = 0; i < 3; i++) {
new Products(baoZiDate,i).start();
}
for (int i = 0; i < 3; i++) {
new Consumer(baoZiDate,i).start();
}
}
}