java多线程设计模式之Two-Phase Termination

Two-Phase Termination

分两阶段终止的意思,它是一种先执行完终止处理再终止线程的模式

先从“操作中” 状态变为“终止处理中”状态,然后再真正的终止线程,这就是Two-Phase Termination模式

该模式的要点如下:

安全地终止线程(安全性)

必定会终止处理(生存性)

发出终止请求会尽快进行终止处理(响应性)

 

程序实例:

CountupThread 表示进行计数的线程的类

Main 测试程序行为的类

CountupThread类:

counter字段表示当前的计数值

shutdownRequested字段是表示是否已发出终止请求(用于判断线程是否要进入“终止处理中”状态)其中volatile关键字是防止线程脏读 

shutdownRequest()方法,当要终止CountupThread线程会调用

interrupt()方法,为了确保线程在sleep()和wait()状态也会被终止

isShutdownRequested()表示检查是否发生了终止请求

doWork()进行模拟实际操作的方法

doShutdown()执行终止处理的方法(这里只显示counter)

public class CountupThread extends Thread{

//计数值

private long counter = 0;

//发出终止请求后变为true

private volatile boolean shutdownRequested =false;

//终止请求

public void shutdownRequest(){

shutdownRequested = true;

interrupt();

}

//检查是否发生了终止请求

public boolean isShutdownRequested(){

return shutdownRequested;

}

//线程体

public final void run(){

try {

while(!isShutdownRequested()){

doWork();

}

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally{

doShutdown();

}

}

//操作

private void doWork() throws InterruptedException{

counter++;

System.out.println("doWork:counter = "+counter);

Thread.sleep(500);

}

private void doShutdown(){

System.out.println("doShutdown:counter = "+counter);

}

}

Main类:

启动线程,然后再10秒后终止该线程

public class Main {

public static void main(String[] args) {

try {

System.out.println("main:begin");

//启动线程

CountupThread t = new CountupThread();

t.start();

Thread.sleep(10000);

//线程的终止请求

System.out.println("main: shutdownRequest");

t.shutdownRequest();

System.out.println("main : join");

//等待线程终止

t.join();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println("main End");

}

}

扩展

ExecutorService接口与Two-Phase Termination模式

用于确认终止处理已执行到哪个阶段的方法

isShutdown 方法用于确认shutdown方法是否已经被调用的方法

isTerminated方法用于确认线程是否已经实际停止的方法

 

isShutdown方法

isTerminated方法

操作中

false

false

终止处理中

true

false

终止

true

true

 

 

java.util.concurrent.CountDownLatch类

java.util.concurrent.CyclicBarrier类

CountDownLatch类可以实现“等待指定次数的CountDown方法被调用”

下面看看关于CountDownLatch的实例:

程序实现了让线程处理10 项MyTask工作并等待10项工作都处理完成的工作

 

MyTask类:

调用doTask执行“实际处理”

调用countDown处理MyTask的run方法的数值减1,当所有的MyTask处理后,计数值将会为0,主线程会从await方法中返回。

public class MyTask implements Runnable{

private final CountDownLatch doneLatch;

private final int context;

private static final Random random = new Random(314159);

public MyTask(CountDownLatch doneLatch,int context){

this.doneLatch = doneLatch;

this.context = context;

}

@Override

public void run() {

// TODO Auto-generated method stub

doTask();

doneLatch.countDown();

}

protected void doTask(){

String name = Thread.currentThread().getName();

System.out.println(name+":MyTask:Begin:context="+context);

try {

Thread.sleep(random.nextInt(3000));

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally{

System.out.println(name+":MyTask:End:context="+context);

}

}

}

 

Main类:

准备工作对象ExecutorService

创建CountDownLatch的实例,初始值为10

调用execute方法执行10个MyTask

调用await方法等待doneLatch的计数为0

调用shutdown方法终止service

 

public class Main {

private static final int TASKS = 10;//工作的个数

public static void main(String[] args) {

System.out.println("main begin");

ExecutorService service = Executors.newFixedThreadPool(5);

CountDownLatch doneLatch = new CountDownLatch(TASKS);

try {

for (int t = 0; t < TASKS; t++) {

service.execute(new MyTask(doneLatch, t));

}

System.out.println("await");

doneLatch.await();

} catch (InterruptedException e) {

}finally{

service.shutdown();

System.out.println("main end");

}

}

}

java.util.concurrent.CyclicBarrier

当想多次重复进行线程同步的时候,使用CyclicBarrier会比较方便

CyclicBarrier可以周期性(cyclic)地创建出屏障barrier,在屏障未解除之前,碰到屏障的线程是无法继续前进的,只有当指定的个数的线程到达屏障处后,屏障才会被解除。

源码实例:

MyTask3:

调用doPhase(phase)方法进行第phase阶段的工作

调用await方法表示自己已经完成了第phase阶段的工作

public class MyTask2 implements Runnable{

private static final int PAHSE = 5;

private final CyclicBarrier phaseBarrier;

private final CountDownLatch doneLatch;

private final int context;

private static final Random random = new Random(314159);

public MyTask2(CyclicBarrier phaseBarrier,CountDownLatch doneLatch,int context){

this.phaseBarrier = phaseBarrier;

this.doneLatch = doneLatch;

this.context = context;

}

@Override

public void run() {

// TODO Auto-generated method stub

try {

for(int phase = 0;phase<PAHSE;phase++){

doPhase(phase);

//在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。

phaseBarrier.await();

}

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (BrokenBarrierException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

protected void doPhase(int phase){

String name = Thread.currentThread().getName();

System.out.println(name+":MyTask2:Begin:context= "+context+" ,phase ="+phase);

try {

Thread.sleep(random.nextInt(3000));

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally{

System.out.println(name+":MyTask2:end:context= "+context+" ,phase ="+phase);

}

}

}

Main类

public class Main2 {

private static final int Threads = 3;

public static void main(String[] args) {

System.out.println("begin");

//由ExecutorService提供进行工作的线程

ExecutorService service = Executors.newFixedThreadPool(Threads);

//屏障被解除时的操作

Runnable barrierAction = new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

System.out.println("Barrier Action!");

}

};

//CyclicBarrier用于使线程步调一致

CyclicBarrier phaseBarrier = new CyclicBarrier(Threads,barrierAction);

//用于确认工作是否结束

CountDownLatch doneLatch = new CountDownLatch(Threads);

try {

for(int t= 0;t<Threads;t++){

service.execute(new MyTask3(phaseBarrier, doneLatch, t));

}

//等待工作结束

System.out.println("await");

//能够阻塞线程 直到调用Threads次doneLatch.countDown() 方法才释放线程

    doneLatch.await();

} catch (InterruptedException e) {

}finally{

service.shutdown();

System.out.println("end");

}

}

}

总结

线程优雅地执行终止处理,然后终止运行

三点提现:

1. 安全地终止 (即使接收到终止请求,线程也不会立即终止)

2.必定会进行终止处理(线程在接收到终止请求后,会中断可以中断的wait,转入终止处理)

3.发出终止请求后会尽快进入终止处理(线程在接收到终止请求后,会中断可以中断的sleep,尽快进入终止处理)

这就是Two-Phase Termination模式

猜你喜欢

转载自blog.csdn.net/qq_31350373/article/details/80513400