首先两阶段终止模式不是23种传统设计模式中的,它是由 黄文海在《Java多线程编程实战指南 设计模式》 中所提到的模式,现一共可归纳为36种设计模式
当我们想要结束一个线程或者关闭jvm的时候,通过此模式可以优雅安全的关闭线程,让线程可以完成它本应完成的当前任务并可以附加一些收尾工作后再进行关闭
此模式下关闭线程会有一定延迟,主要在于被关闭线程需要执行完后,再进行关闭
首先Java jdk中并没有关于安全的直接的停止线程的Api 我知道你想到了Interrupt
Interrupt快速解读传送门 http://blog.csdn.net/crazyzxljing0621/article/details/56666418
此模式的设计其实没什么精髓之处,其实就是线程中不断对一个参数进行验证,满足条件时线程跳出并执行结束后的收尾工作,最后安全关闭。
在表现此模式以前我们先把volatile再复习一下 传送门http://www.ibm.com/developerworks/cn/java/j-jtp06197.html
volatile的简单例子
public class s1 { public volatile static int v1 = 0; public static int v2 = 0; public static int v3 = 0; public volatile static int v4 = 0; public static AtomicInteger v5 = new AtomicInteger(0); public static void inc() { try { Thread.sleep(3); } catch (InterruptedException e) { } v1++; v2++; v5.getAndIncrement(); synchronized (s1.class) { v3++; v4++; } } public static void main(String[] args) throws InterruptedException { Thread threads[]=new Thread[1000]; for (int i = 0; i < 1000; i++) { threads[i]=new Thread(new Runnable() { @Override public void run() { inc(); } }); threads[i].start(); } for(Thread t:threads) t.join(); System.out.println("运行结果v1:Counter.count=" + s1.v1); System.out.println("运行结果v2:Counter.count=" + s1.v2); System.out.println("运行结果v3:Counter.count=" + s1.v3); System.out.println("运行结果v4:Counter.count=" + s1.v4); System.out.println("运行结果v5:Counter.count=" + s1.v5); } }
运行结果v1:Counter.count=994 运行结果v2:Counter.count=998 运行结果v3:Counter.count=1000 运行结果v4:Counter.count=1000 运行结果v5:Counter.count=1000
好了我们开始展现这个【两阶段终止模式】
先来看最简单的实现方式
/** * * @author Allen * @date 2017年2月21日 * */ public class e1 implements Runnable { private volatile boolean closeThread = false; private int i; // 终止请求 public void shutdownRequest() { closeThread = true; Thread.currentThread().interrupt(); } public void close() { this.closeThread = true; } public boolean isCloseThread() { return closeThread; } // 具体动作 public final void run() { try { while (!closeThread) { System.out.println("维修进度" + ++i + "%"); Thread.sleep(1); } } catch (InterruptedException e) { } finally { try { overFun(); } catch (InterruptedException e) { e.printStackTrace(); } } } // 终止处理 private void overFun() throws InterruptedException { Thread.sleep(1000); System.out.println(">>>>>正在收拾工具"); Thread.sleep(1000); System.out.println(">>>>>正在把玛莎拉蒂开出车库"); Thread.sleep(1000); System.out.println(">>>>>正在用玛莎拉蒂车载电话呼叫领导的手机"); Thread.sleep(1000); System.out.println(">>>>>我:领导你好,土豪我今天的总维修进度 " + i + "%"); } }
首先我们的标示使用volatile修饰,我们仅仅用它做了一个布尔型的判定用参数,满足了其可见性,又不对他进行频繁修改而去触摸那原子性问题
上面代码我们每次都判断closeThread是否为真,如果if满足则进入finally并执行overFun以安全结束线程及其业务,保证了我们数据、业务的安全性
public static void main(String[] args) { System.out.println("开始修电脑"); try { e1 e = new e1(); Thread t = new Thread(e); t.start(); Thread.sleep(new Random().nextInt(30)+69); System.out.println("大喇叭广播: ~都快别修了"); e.close(); t.join(); System.out.println("领导:..你居然开玛莎拉蒂"); } catch (InterruptedException e) { e.printStackTrace(); } }
打印结果
开始修电脑 维修进度1% 维修进度2% 维修进度3%
...
... 维修进度40% 维修进度41% 维修进度42% 维修进度43% 大喇叭广播: ~都快别修了
正在收拾工具 正在把玛莎拉蒂开出车库 正在用玛莎拉蒂车载电话呼叫领导的手机 我:领导你好,开着玛莎拉蒂的我今天总维修进度 43% 领导:..你居然开玛莎拉蒂
下面看这个例子,其实就是做的复杂一些的两阶段中止模式,启动服务器,运行所有活动,关闭活动的时候每个活动都会调用overEvent
package TwoPhaseTerminationPattern.complex.sys.inf; import TwoPhaseTerminationPattern.complex.ThreadOverException; /** * 游戏系统 * @author Administrator * */ public abstract class IGameSys { private long time; private String name; public IGameSys(long time, String name) { this.time = time; this.name = name; } public String name() { return this.name; } public long time() { return this.time; } public abstract void event(Object... ob) throws ThreadOverException; public abstract void overEvent(); } package TwoPhaseTerminationPattern.complex.sys; import TwoPhaseTerminationPattern.complex.ThreadOverException; import TwoPhaseTerminationPattern.complex.sys.inf.IGameSys; /** * 活动系统实现 * * @author Allen * @date 2017年2月21日 * */ public class ActivitySys extends IGameSys { public ActivitySys(long time, String name) { super(time, name); } private boolean temp = false; @Override public void event(Object... ob) throws ThreadOverException { if (!temp){ System.out.println("<Thread-" + super.name() + ">[event]活动系统运行中 ><"); temp=true; } } @Override public void overEvent() { System.out.println("<Thread" + super.name() + ">[overEvent]"); } } package TwoPhaseTerminationPattern.complex.sys; import TwoPhaseTerminationPattern.complex.ThreadOverException; import TwoPhaseTerminationPattern.complex.sys.inf.IGameSys; /** * 公告系统实现 * * @author Allen * @date 2017年2月21日 * */ public class MsgSys extends IGameSys { public MsgSys(long time, String name) { super(time, name); } private boolean temp=false; @Override public void event(Object... ob) throws ThreadOverException { if (!temp){ System.out.println("<Thread-" + super.name() + ">[event]系统公告运行中 ><"); temp=true; } } @Override public void overEvent() { System.out.println("<Thread" + super.name() + ">[overEvent]"); } } package TwoPhaseTerminationPattern.complex; public interface IRepairModel extends Runnable { } package TwoPhaseTerminationPattern.complex; import TwoPhaseTerminationPattern.complex.sys.inf.IGameSys; public class RepairModelImpl implements IRepairModel { private IGameSys ir; public RepairModelImpl(IGameSys ir) { this.ir = ir; } @Override public void run() { System.out.println(ir.name() + "已启动"); try { while (true) { Thread.sleep(ir.time()); if (SystemState.getInstance().isState()) break; ir.event(); } } catch (ThreadOverException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } finally { ir.overEvent(); } return; } } package TwoPhaseTerminationPattern.complex; import java.util.Arrays; import java.util.Iterator; import TwoPhaseTerminationPattern.complex.sys.ActivitySys; import TwoPhaseTerminationPattern.complex.sys.MsgSys; import TwoPhaseTerminationPattern.complex.sys.inf.IGameSys; /** * * @author Allen * @date 2017年2月22日 * */ public class run { static IGameSys[] igame = { new MsgSys(500,"公告系统"), new ActivitySys(200,"活动系统") }; public static void main(String[] args) throws InterruptedException { System.out.println("游戏服务器已启动"); startThreadGroup(); Thread.sleep(4000); SystemState.getInstance().sendState(); } private static void startThreadGroup() throws InterruptedException { Iterator<IGameSys> it = Arrays.asList(igame).iterator(); while (it.hasNext()) { Thread thread = new Thread(new RepairModelImpl(it.next())); thread.start(); } } } package TwoPhaseTerminationPattern.complex; /** * 修复状态 * * @author Allen * @date 2017年2月21日 * */ public final class SystemState { /** * 饿汉单例 */ private static SystemState instance = new SystemState(); private SystemState() { } public static SystemState getInstance() { return instance; } private volatile boolean state = false; public boolean isState() { return state; } /** * 发送状态 * @author Allen * @date 2017年2月21日 */ public void sendState() { this.state = true; } } package TwoPhaseTerminationPattern.complex; public class ThreadOverException extends Exception { /** * */ private static final long serialVersionUID = 1L; }
输出结果:
游戏服务器已启动 公告系统已启动 活动系统已启动
<Thread-活动系统>[event]活动系统运行中 ><
<Thread-公告系统>[event]系统公告运行中 ><
[overEvent]
IGameSys 系统服务模型
定义了系统执行周期,系统名,规范了event和overevent,IgameSys及其派生类无需关心Thread细节,只需完成event/overevent业务操作即可
IRepairModel 空接口继承了runnable
** 日后扩展,内容规范,依赖规范
RepairModelImpl 线程细节实现
对IgameSys进行了两阶段终止模式实现
SystemState 修复状态容器
单例且volatile,sendState开闭
就到这里了。代码还有很多可以优化的地方,不过毕竟是个例子,目的为了了解两阶段终止模式的使用
原文链接:https://blog.csdn.net/crazyzxljing0621/article/details/56669649