1. 两阶段终止模式
Two Phase Termination
在线程T1中优雅的终止线程T2,优雅的意思是给线程T1一个料理后事的计划
1.1 错误思路
-
直接使用stop()来强制杀死线程:这样如果线程锁住了某一个共享资源,他被强制杀死就没有机会释放锁,其他的线程没法获得锁
-
使用System.exit(int):这个直接杀死了进程,也不是我们想要的
1.2 两阶段终止模式
可以用在:系统的健康状态监控,用一个后台的监控线程来定时监控,当我们需要让他停止就能让他停止
实现的思路就是
① 一个后台监控线程每两秒进行一次监控(while)
② 如果让他停止就让他调用interrupt()方法
③ 如果当前线程正在睡眠,那么调用interrupt()方法会抛出异常,我们在异常设置打断状态为true
④ 如果打断状态为true,则跳出循环终止线程
class TwoPhaseTermination{
private Thread monitor;
//启动线程
public void start(){
monitor = new Thread(()->{
while(true){//每一秒执行一次监控
Thread current = Thread.currentThread();
if(current.isInterrupted()){
System.out.println("料理后事");
break;
}
try {
Thread.sleep(1000);//sleep的时候被打断会出现异常并且重置打断标记为false
System.out.println("执行监控");
} catch (InterruptedException e) {
current.interrupt();//设置打断标记为真
}
}
});
monitor.start();
}
//终止线程
public void stop(){
monitor.interrupt();
}
}
2. 生产者消费者模型
- 消费队列可以用来平衡生产和消费的线程资源
- 生产者仅仅负责产生数据,不关心数据怎么处理,消费者专心处理结果数据
- 消息队列是有容量限制的,满时不会再加入数据,空时不会再消耗数据
- JDK 中各种阻塞队列,采用的就是这种模式
class Message {
private int id;
private Object message;
public Message(int id, Object message) {
this.id = id;
this.message = message;
}
public int getId() {
return id;
}
public Object getMessage() {
return message;
}
}
class MessageQueue {
private LinkedList<Message> queue;
private int capacity;
public MessageQueue(int capacity) {
this.capacity = capacity;
queue = new LinkedList<>();
}
public Message take() { //获取消息
synchronized (queue) {
while (queue.isEmpty()) {
log.debug("没货了, wait");
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Message message = queue.removeFirst();
queue.notifyAll();//唤醒
return message;
}
}
public void put(Message message) { //存入消息
synchronized (queue) {
while (queue.size() == capacity) {
log.debug("库存已达上限, wait");
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.addLast(message);
queue.notifyAll();//唤醒
}
}
}