java 多线程模式_《图解Java多线程设计模式》之五:Balking 模式

一,什么是Balking模式

如果现在不合适执行这个操作,或者没必要执行这个操作,就停止处理,直接返回。

在Balking模式中,如果守护条件不成立,就立即中断处理。

二,例子:

定期将当前数据内容写入文件中,比如文本工具的自动保存功能,定期的将数据保存到文件中。

当数据内容被写入时,会完全覆盖上次写入的内容,只有最新的内容才会被保存

当写入的内容和上次的内容完全相同时,再向文件写入就多余了,所以就不再执行写入操作。

所以这个程序就是以 数据内容不同 作为守护条件,如果数据内容相同,就不执行写入操作,直接返回(balk)

代码:

Data类:可以修改并保存的数据的类

ChangerThread类:模仿用户,进行文本的修改并随时保存

SaverThread类:执行自动保存的线程

public classData {private finalString filename;privateString content;private booleanchanged;publicData(String filename, String content) {this.filename =filename;this.content =content;this.changed = true;

}//修改了数据内容

public synchronized voidchange(String newContent){

content=newContent;

changed= true;

}//若数据修改过,则保存到文件中

public synchronized void save() throwsIOException{if (!changed){//如果没有修改,就不保存了

return;

}

doSave();

changed= false;

}//将数据内容保存到文件中

public void doSave() throwsIOException{

System.out.println(Thread.currentThread().getName()+" calls doSave, content ="+content);

Writer writer= newFileWriter(filename);

writer.write(content);

writer.close();

}

}

public class ChangerThread extendsThread{private finalData data;private final Random random = newRandom();publicChangerThread(String name,Data data) {super(name);this.data =data;

}

@Overridepublic voidrun() {try{for (int i = 0; true; i++) {

data.change("NO."+i);//修改数据

Thread.sleep(random.nextInt(1000));//执行其他操作

data.save();//显示的保存,用户自己点击保存

}

}catch(IOException e){

e.printStackTrace();

}catch(InterruptedException e){

e.printStackTrace();

}

}

}

public class SaverThread extendsThread{private finalData data;publicSaverThread(String name,Data data) {super(name);this.data =data;

}

@Overridepublic voidrun() {try{while (true){

data.save();//要求保存数据

Thread.sleep(1000);//休眠约一秒

}

}catch(IOException e){

e.printStackTrace();

}catch(InterruptedException e){

e.printStackTrace();

}

}

}

public classTest {public static voidmain(String[] args) {

Data data= new Data("data.txt","(empty)");new ChangerThread("ChangeThread",data).start();new SaverThread("SaverThread",data).start();

}

}

三,GurardedObject:被防护的对象

GuardedObject角色是一个拥有被防护的方法的类。当线程执行guardedMethod时,若守护条件成立,则执行实际的处理。

当守护条件不成立时,不执行实际的处理,直接返回。守护条件是否成立,会随着GuardedObject角色的状态变化而变化

Data类就是被防护的对象

save方法对应guardedMethod

change方法对应stateChangingMethod

四,何时使用Balking模式

1.并不需要执行时:

比如上面的程序中,文件已经手动保存了,并且文本内容也没有改变,就不需要再执行自动保存了。这样可以提高程序性能

2.不需要等待守护条件成立时

当守护条件不成立时,就立即返回并进入下一个操作,就可以使用这种模式。这能够提高程序的响应性

3.守护条件仅在一次成立时

相当于没有stateChangingMethod方法的情况

例子:

public classSomething{private boolean initialized = false;public synchronized voidinit(){if(initialized){return;

}

doInit();

initialized= true;

}public voiddoInit(){//实际处理初始化

}

}

//如果没有初始化,就做一次初始化动作。如果已经初始化就什么也不做。直接返回

五,balk结果的表示方式

1.忽略balk

不通知调用端发生了balk,比如实例程序中直接return

2.通过返回值来表示balk

比如返回值为true,表明为发生balk。如果返回值为false,说明发生了balk,处理并未被执行

3.通过异常来表示balk的发生

当balk发生时,程序并不是从方法中retrun,而是直接抛出异常

六,超时

Balking模式中,当守护条件不成立时,线程会直接balk并返回

而Guarded Suspension模式中,当守护条件不成立时,线程会一直等待到成立为止。

这两种模式都比较极端。还有一种处理方方法,在守护条件成立之前等待一段时间,如果到时条件还未成立,则直接balk。这种处理称为 guarded timed或timeout

1.wait何时终止?

当执行: obj.wait();时,线程进入obj的等待队列,停止运行,并释放持有的obj锁。当下面情况发生时,线程就会退出等待线程:

notify方法执行

notifyAll方法执行

interrupt方法执行

超时发生时

2.guarded timed的实现

从上面的方法得知,我们无法区分wait方法是被notify/notifyAll了,还是超时了,所以自己要实现guarded timed。判断wait是否超时

代码:

public classHost {private final long timeout;//超时时间

private boolean ready = false;//方法正常执行时为true

public Host(longtimeout){this.timeout =timeout;

}//修改状态

public synchronized void setExecutable(booleanon){

ready=on;

notifyAll();

}//检查状态后在执行

public synchronized void execute()throwsInterruptedException,TimeoutException{long start = System.currentTimeMillis();//开始时间

while (!ready){long now = System.currentTimeMillis();//当前时间

long rest = timeout - (now -start);

//在这里只要 <=0,我们就认为超时。(因为wait方法的参数为0时,就表示没有超时时间(超时时间无限长),当传入负数时,会抛出IllegalArgumentException异常。)if (rest <= 0){throw new TimeoutException("now - start= "+(now-start)+", timeout = "+timeout);

}

wait(rest);

}

doExecute();

}//实际的处理

private voiddoExecute(){

System.out.println(Thread.currentThread().getName()+" calls doExecute");

}

}

/*

如果Host的方法执行时,不调用setExecutable(true),程序就会出现超时*/

public classTest {public static voidmain(String[] args) {

Host host= new Host(10000);try{

System.out.println("execute Begin");

host.execute();

}catch(TimeoutException e){

e.printStackTrace();

}catch(InterruptedException e){

e.printStackTrace();

}

}

}

执行结果:

execute Begin

java.util.concurrent.TimeoutException: now - start= 10001, timeout = 10000  //误差1毫秒

at com.amazing.jdk.myThread.package12.Host.execute(Host.java:29)

at com.amazing.jdk.myThread.package12.Test.main(Test.java:14)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值