我们学习的进度已经到了多线程的阶段,由于线程传输的特性及多个线程访问同一资源时发生的线程安全问题,消费者与生产者这个很有名的案例也出现在我们面前,今天也特意拿来和大家分享一下,老师给的题目如下:
根据今天的案例(生成者消费者设计模式),设计AK47机枪,要求子弹打完就上子弹30颗(生产者),上满后开枪(消费者)打完30颗子弹,子弹为0时就上子弹30颗,然后循环往复。。。
然后下面我们开始解决问题:
第一步:我们首先要创建三个类,如 生产者 Product 消费者 Customer 和 AK47
最后在创建个测试类 这个类的框架就完成了
第二步:我们在AK47这个类中首先要定义一个Integer变量用来存储子弹的数量,还要在定义一个布尔变量用来切换射击和装弹的线程,然后在AK47中在通过同步(Synchronized)设计枪的两种具体模式
第三步:让生产者和消费者 实现 Runnable j接口 并且创建一个 AK47的全局变量用来接受AK47产生的实例,作用是这两个线程在开启状态下访问统一资源
第四步:在测试类中实现AK47的实例,并将其作为参数传输到生产者和消费者当中,最后创建这两个 线程,并开启线程
步骤虽然很简单,但是这些涉及到的东西对于第一次接触线程的同学老说确实有点晦涩难懂,比如wait 和 notify 以及 wait 和 sleep 这些方法的组合及区分都要搞清楚。还有同步器的使用也是一个重点,下面代码演示,如果程序有什么问题或者有什么想不通,欢迎留言,,我们一起讨论,一起进步!
首先是AK47:
package com.gg.thread.homework01;
public class AK47 {
//子弹的数量
private Integer bullet = 0;
private boolean isTrue = false;//true 发射子弹 false 填充子弹
/**
* 功能:增加子弹
* author:queyr
* @param:
* time:2018年8月22日下午5:05:30
*/
public synchronized void addBullet() {
if(bullet==30) {
isTrue = true;
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(!isTrue) {
bullet++;
System.out.println("当前已经填装"+bullet+"颗子弹");
}
this.notifyAll();
}
/**
* 功能:发射子弹
* author:queyr
* @param:
* time:2018年8月22日下午5:05:33
*/
public synchronized void shootBullet() {
if(bullet==0) {
isTrue = false;
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(isTrue) {
System.out.println("当前已经发射第"+bullet+"颗子弹");
bullet--;
}
this.notifyAll();
}
}
其次是生产者:
package com.gg.thread.homework01;
public class Product implements Runnable{
//创建AK47的实例用来接受传入的参数
private AK47 ak47 = null;
public Product(AK47 ak47) {
this.ak47 = ak47;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
ak47.addBullet();
}
}
}
接下来是消费者:
package com.gg.thread.homework01;
public class Customer implements Runnable{
private AK47 ak47 = null;
public Customer(AK47 ak47) {
this.ak47 = ak47;
}
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
ak47.shootBullet();
}
}
}
最后一个是测试案例:
package com.gg.thread.homework01;
public class AK47Test {
public static void main(String[] args) {
AK47 ak47 = new AK47();
//生产者和消费者访问同一资源
Product p = new Product(ak47);
Customer c = new Customer(ak47);
new Thread(p).start();
new Thread(c).start();
//让主线程进入休息状态,防止主线程提前结束,虚拟机进入关闭状态
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
今天就和大家分享到这里!我们下次再见!
-------------------