实验内容:
以读者订阅报刊杂志为背景,体验多线程生产/订阅模式下的经典应用。
具体业务描述:
本实验以实际生活中报刊杂志的订阅为业务背景。订阅者通常有很多种,他们可以
同时向出版社发出订阅申请; 出版社通常根据自身的资源条件对收到的订阅申请做统
一的处理;出版社通常能接受并处理的订阅申请量是有一定限度的;出版社汇总订阅申
请信息后交由独立业务单元处理,直至完毕;本业务主要是模拟多读者同时订阅、信息
汇总后再行处理的业务情景。
本实验的关键业务概念:
1) 订阅者,即订阅信息生产者,向共享池中放入订阅信息;
2) 信息汇总,即订阅信息共享池,生产者和消费者共用;
3) 业务单元,即订阅信息消费者,处理订阅者生产的订阅信息。
创建工程并配置环境:
1) 工程名:SE_JAVA_EXP_E03。
2) 创建包,取名:cn.com.java.experiment 和 cn.com.java.experiment.entity。
3) 在 包 cn.com.java.experiment.entity 下 创建订阅信息共享池业务类:SharePool。
- 设置两个属性,只为 pool 属性实现 setter/getter 方法;
- 为 SharePool 类创建构造器,初始化最大限量的订阅信息;
- 创建生成订阅信息的方法 produce,由订阅者调用,生成订阅信息并完成订阅信息的提交,实现要求如下:
1.应用同步机制控制本方法的实现;
2.获取当前订阅信息共享池的信息数量;
3.当共享池信息数量等于最大订阅量时,输出如下信息并开始等待:“订阅请求队列已满,等待系统处理订阅请求中……”
4.当共享池信息数量小于最大订阅量时:把订阅信息加入到共享池;在控制台输出如下格式的信息:“订阅者@”+当前线程名+":订阅《" + media + “》申请已提交.当前订阅数量为:” + 订阅数量;发出完成订阅申请的通知。 - 创建处理订阅信息的方法 consum,由订阅信息消费者调用,完成订阅信
息的处理。实现要求如下:
1…应用同步机制控制本方法的实现;
2.获取当前订阅信息共享池的信息数量;
3.当共享池信息数量等于 0 时,输出如下信息并开始等待:“处理者@” +当前线程名称+“暂无订阅请求信息,等待中……”
4.当共享池信息数量不为 0 时:从订阅共享池移除一项订阅信息;在控制台输出如下格式的信息:“处理者@”+当前线程名+":处理《" + 移除订阅信息 + “》订阅已完毕。尚待处理订阅数量为:” + 剩余订阅数量;发出完成订阅处理的通知。
4) 在 cn.com.java.experiment.entity 包中创建订阅信息生产者业务类:Producer
- Producer 类需要实现线程类接口 Runnable,并且实现 run 方法;
- 为 Producer 类创建订阅信息共享池属性,要求如下:
- 为 Producer 类创建构造器;
- 为 Producer 类实现生产订阅信息的 run 方法,以产生指定数量订阅信息并
存放到订阅共享池中。实现要求如下:
1.模拟输出订阅者相关信息,格式如下: “订阅者@”+当前线程名称+“:订阅”+订阅数量+“份。”;
2.通过循环方式发出所有指定数量的订阅请求:当订阅数量发送完毕后,结束订阅并输出如下信息: “订阅者@”+当前线程名称+“->完成订阅。”定义计数器,把信息放入到订阅信息共享池并输出如下信息:“订阅者@”+当前线程名称+“ 在提交第”+计数器+“ 份订阅申请。”让当前线程休眠半秒钟;订阅完毕后退出方法。
5) 在 cn.com.java.experiment.entity 包中创建订阅信息处理者业务类:Consumer
- Consumer 类需要实现线程类接口 Runnable,并且实现 run 方法;
- 为 Consumer 类创建订阅信息共享池属性,要求如下:
- 为 Consumer 类创建构造器;
- 为 Consumer 类实现生产订阅信息的 run 方法,产生指定数量的订阅信息并存放到订阅信息共享池中。实现要求如下:
1.创建处理订阅信息数量的计数器;
2.通过循环方式处理共享池内的所有订阅信息:启动计数器,当计数器大于15 时,结束处理并输出如下信息:“本线程完成订阅处理量,即刻退出。处理者@”+当前线程名称;当计数器小于 15 时,处理共享池内的订阅信息并输出如下信息:“订阅者@”+当前线程名称+“ :处理第”+计数器+“ 份订阅。”处理全部完成后,退出信息订阅池。
6) 在包 cn.com.java.experiment 下创建主类:MainClass,模拟现实生产/处理的结
果。
- 为 MainClass 创建入口主方法:main;
- 在 main 中,创建 1 个订阅信息共享池对象;
- 在 main 中,创建 5 个不同的订阅者,订阅总量为 15,共用共享池;
- main 中,创建 1 个订阅处理类对象,处理所有提交的订阅信息。
代码
Mainclass
package cn.com.java.experiment;
import cn.com.java.experiment.entity.Consumer;
import cn.com.java.experiment.entity.Producer;
import cn.com.java.experiment.entity.SharePool;
public class MainClass {
public static void main(String[] args) {
SharePool pool = new SharePool();
for (int i = 1; i <= 5; i++) {
new Thread(new Producer(pool, i)).start();
}
new Thread(new Consumer(pool)).start();
}
}
Consumer
package cn.com.java.experiment.entity;
public class Consumer implements Runnable {
private SharePool pool;
public Consumer() {
super();
}
public Consumer(SharePool pool) {
super();
this.pool = pool;
}
public void run() {
int counts = 1;
while(true)
{
if(counts <= 15) {
System.out.println("处理者@" + Thread.currentThread().getName() + ":处理第" + counts + "份订阅。");
this.pool.consume();
}else
{
System.out.println("本线程完成订阅处理量,即刻退出。处理者@" + Thread.currentThread().getName());
break;
}
counts++;
}
}
}
Producer
package cn.com.java.experiment.entity;
public class Producer implements Runnable {
private SharePool pool;
private int count;
public Producer() {super();}
public Producer(SharePool pool, int count) {
super();
this.pool = pool;
this.count = count;
}
public void run() {
String infor = "报刊杂志";
int counts = 0;
System.out.println("订阅者@" + Thread.currentThread().getName() + ":订阅" + count + "份。");
while (count > 0) {
counts++;
System.out.println("订阅者@" + Thread.currentThread().getName() + " 在提交第" + counts + " 份订阅申请。");
pool.produce(infor + counts);
count--;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("订阅者@" + Thread.currentThread().getName() + "->完成订阅。");
}
}
Sharepool
package cn.com.java.experiment.entity;
import java.util.ArrayList;
import java.util.List;
public class SharePool {
private List<String> pool=new ArrayList();
private final int MAX=15;
public List<String> getPool(){return pool;}
public void setPool(List<String> pool) {this.pool = pool;}
public SharePool() {
super();
}
public void produce(String infor) {
synchronized (this) {
if (pool.size() == MAX) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("订阅请求队列已满,等待系统处理订阅请求中......");
}
else {
pool.add(infor);
System.out.println("订阅者@" + Thread.currentThread().getName() + ":订阅《" + infor + "》申请已提交.当前订阅数量为:" + pool.size());
try{
notify();
}
catch(Exception e )
{
e.printStackTrace();
}
}
}
}
public void consume() {
synchronized (this) {
if (pool.size() == 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("处理者@" + Thread.currentThread().getName() + "暂无订阅请求信息,等待中......");
}
else {
String infor = pool.remove(0);
System.out.println("处理者@" + Thread.currentThread().getName() + ":处理《" + infor + "》订阅已完毕。尚待处理订阅数量为:" + pool.size());
try{
notify();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
}
截图