我是野猪。
题目的要求如下:
“计算机系统中存在多个具有I/O操作的组件,比如内存、硬盘、声卡等;这些I/O组件都具有读和写的操作。
假设计算机系统要对这些I/O组件的操作统一管理,并把它们的操作(由用户代码触发)存放到系统中的唯一的一个队列中。
假设当前系统有两个线程,可以通过一个统一的接口处理队列中命令,但只能互斥的访问该队列;
此外,线程处理一个命令之后,为了便于观看,都随机的等待1-4s。
请选择合适的模式来模拟这个过程。PS:不考虑I/O组件自身读写的互斥问题,输出一跳语句来表示读、写操作即可。”
分析过程:
1.创建具体的组件,比如RAM和DIESK(内存和硬盘);
2.创建具体的指令;
3.创建存放指令的队列(为保证只能互斥访问该队列设计成单列模式);
4.运行时,指令放入队列中,创建线程,启动线程,查看运行结果。
1.创建组件(抽象父类和其有具体实现的子类):
/**
* 代指计算机中任何一个器件
* 功能输入和输出
* 真正能执行组件读、写操作的是组件本身;
*/
public abstract class Compent {
protected final String name;
public Compent(String name) {
this.name = name;
}
public abstract void read();
public abstract void write();
}
/**
* 具体的控件
* Ram 内存
*/
public class RAM extends Compent {
public RAM(String name) {
super(name);
}
@Override
public void read() {
System.out.println(name + " is reading");
}
@Override
public void write() {
System.out.println(name + " is writtng");
}
}
/**
* 具体控件 DIESK
*/
public class DIESK extends Compent {
private DIESK(String name) {
super(name);
}
@Override
public void read() {
System.out.println(name + " is reading");
}
@Override
public void write() {
System.out.println(name + " is writting");
}
}
2.创建命令(命令的父类和具体到每一个I/O组件上的读写命令):通过一个统一的接口处理队列中命令;代码如下,很简单:
/**
* 接口 职责就是执行命令
*/
public interface Command {
void execute();
}
/**
* 具体的硬盘读命令
*/
public class DieskReadCommand implements Command {
Compent diesk;
public DieskReadCommand(Compent compent) {
this.diesk = compent;
}
@Override
public void execute() {
//执行什么?执行的是内存的读操作
diesk.read();
}
}
/**
* 具体的硬盘写命令
*/
public class DieskWriteCommand implements Command {
Compent diesk;
public DieskWriteCommand(Compent compent) {
this.diesk = compent;
}
@Override
public void execute() {
//执行什么?执行的是内存的读操作
diesk.write();
}
}
/**
* 具体的内存读命令
*/
public class RamReadCommand implements Command {
Compent ram;
public RamReadCommand (Compent compent) {
this.ram = compent;
}
@Override
public void execute() {
//执行什么?执行的是内存的读操作
ram.read();
}
}
/**
* 具体的内存的写命令
*/
public class RamWriteCommand implements Command {
Compent ram;
public RamWriteCommand(Compent compent) {
this.ram = compent;
}
@Override
public void execute() {
//执行什么?执行的是内存的读操作
ram.write();
}
}
3.使用单例模式创建存放指令的队列(队列应该具有插入和获取指令的方法):
import java.util.LinkedList;
import java.util.Queue;
/**
* 存放具体操作命令的队列
* 线程不和任务直接沟通合适传话人
*/
public class CommandQueueSingleTon {
private static CommandQueueSingleTon commandQueueSingetion = null;
//存放命令的队列 之所以使用linkedlist 因为命令的读写操作频繁
Queue<Command> commandQueue = new LinkedList<Command>();
//1.私有构造
private CommandQueueSingleTon() {
}
//2.对外暴露方法(获取一个有权限的引用指向这个实例)
public static CommandQueueSingleTon getQueueSinglton() {
if (commandQueueSingetion == null) {
synchronized (CommandQueueSingleTon.class) {
if (commandQueueSingetion == null) {
commandQueueSingetion = new CommandQueueSingleTon();
}
}
}
return commandQueueSingetion;
}
//4.以上是单例的书写方式 下面就是提供方式让命令插入队列和取出队列
public void insertCommand(Command cmd) {
commandQueue.add(cmd);
}
public Command getCommand() {
if (commandQueue != null) {
Command command = commandQueue.poll();
return command;
} else {
return null;
}
}
}
4.main函数中测试,基本流程也是①创建I/O组件;②根据组件创建具体的命令;③命令入队;④创建两个线程,从队列中读取调用命令:
/**
* 测试
*/
public class Test {
public static void main(String[] args) {
//1.执行命令的控件
Compent ram = new RAM("RAM");
Compent diesk = new RAM("Cpu");
//2.传话人
Command ramReadCommand = new RamReadCommand(ram);
Command ramWriteCommand = new RamWriteCommand(ram);
Command dieskReadCommand = new DieskReadCommand(diesk);
Command dieskWritteCommand = new DieskWriteCommand(diesk);
//3.命令入列
CommandQueueSingleTon commandQueue = CommandQueueSingleTon.getQueueSinglton();
commandQueue.insertCommand(ramReadCommand);
commandQueue.insertCommand(ramWriteCommand);
commandQueue.insertCommand(dieskReadCommand);
commandQueue.insertCommand(ramWriteCommand);
commandQueue.insertCommand(dieskWritteCommand);
//4。创建线程
Runnable commandProcessor1 = new CommandProcess();
Runnable commandProcessor2 = new CommandProcess();
//start 并不是启动线程而是代表只是把线程放到cpu执行队列中
Thread thread1 = new Thread(commandProcessor1);
thread1.start();
Thread thread2 = new Thread(commandProcessor2);
thread2.start();
}
static class CommandProcess implements Runnable {
@Override
public void run() {
while (true) {
try {
//随机睡上1-4s
Random RAND = new Random(1);
Thread.sleep(RAND.nextInt(4*1024));
CommandQueueSingleTon queueSinglton = CommandQueueSingleTon.getQueueSinglton();
Command command = queueSinglton.getCommand();
if (command != null) {
command.execute();
} else {
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
ps:这段代码比较简单,其中用到的随机数和伪随机数的概念在另一篇文章有简单介绍,线程的介绍也是,大家有需要的话可以自行阅览。如果对以上代码有疑问的话,希望大家能随时指出。