目录
定义
结构
案例
优点
缺点
使用场景
JDK源码解析
Thread中start与run方法的区别
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加与管理。
命令模式包含以下主要角色:
- 抽象命令类角色: 定义命令的接口,声明执行的方法。
- 具体命令角色:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
- 实现者/接收者角色: 接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
- 调用者/请求者角色: 要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
抽象命令类
public interface Command {
void execute();
}
具体命令类
public class OrderCommand implements Command {
//接收者对象
private SeniorChef receiver;
private Order order;
public OrderCommand(SeniorChef receiver, Order order) {
this.receiver = receiver;
this.order = order;
}
@Override
public void execute() {
System.out.println("去执行"+order.getTableNum()+"桌子的订单");
Set ordersName = this.order.getOrder().keySet();
for (String name : ordersName) {
receiver.makeFood(name,order.getOrder().get(name));
}
}
}
接收类
public class SeniorChef {
public void makeFood(String name,Integer number){
System.out.println("厨师提供了:"+name+number+"份");
}
}
//订单类。作为信息传递的媒介
public class Order {
//订单号
private String tableNum;
//存储菜名与数量
private Map order = new HashMap<>();
public Order(String tableNum) {
this.tableNum = tableNum;
}
public String getTableNum() {
return tableNum;
}
public void setTableNum(String tableNum) {
this.tableNum = tableNum;
}
public Map getOrder() {
return order;
}
public void setOrder(String name, Integer number) {
order.put(name,number);
}
}
调用类
public class Waiter {
private List commands;//可以存储多个命令
public Waiter() {
commands = new ArrayList<>();
}
public void setCommand(Command command) {
commands.add(command);
}
public void call(){
System.out.println("服务生发出命令给厨师");
for (int i = 0; i < commands.size(); i++) {
commands.get(i).execute();
}
}
}
测试
public class Client {
public static void main(String[] args) {
SeniorChef receive = new SeniorChef();
Order order = new Order("1号");
order.setOrder("食物A",2);
Command command = new OrderCommand(receive, order);
Waiter waiter = new Waiter();
waiter.setCommand(command);
waiter.call();
}
}
服务生发出命令给厨师
去执行1号桌子的订单
厨师提供了:食物A2份
主要实现了请求者与接收者之间的解耦。
Runable是一个典型命令模式,Runnable担当命令的角色,Thread充当的是调用者,start方法就是其执行方法(Thread重写了Runnable中的run方法应该也是执行方法。)
这是抽象命令类,只有一个抽象方法run()。
这是调用者类,里面包含了Runable类的对象。
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
在调用方法中会调用一个native方法start0(),调用系统方法,开启一个线程。而接收者是对程序员开放的,可以自己定义接收者。
//具体命令类
public class TurnOffThread implements Runnable {
//接收者
private Receive receive;
public TurnOffThread(Receive receive) {
this.receive = receive;
}
@Override
public void run() {
receive.turnOff();
}
}
//接收者类由程序员自己定义
public class Receive {
public void turnOff(){
System.out.println("关闭线程");
}
}
public class Client {
public static void main(String[] args) {
//接收者,自定义的
Receive receive = new Receive();
//具体命令角色,指定了接收者用于调用接收者的方法
Runnable runnable = new TurnOffThread(receive);
//调用者
//这里Thread指定了Runnable对象,那么在Thread初始化时,就会将该对象存储在创建出来的Thread对象中,Thread中的run方法调用的就是指定的Runnable对象
Thread thread = new Thread(runnable);
System.out.println(thread.getName()+"开始执行");
thread.start();
thread.run();
}
}
Thread-0开始执行
关闭线程
关闭线程
如果在客户端直接使用run方法相当于是在当前线程执行方法,并不会创建一个新的线程去执行。而start方法是创建出一个新的线程后,在新线程中去执行run方法。
源码中,start方法中调用了系统方法start0方法,作用是创建一个线程。而run方法是通过JVM自动调用。