1. 该模式的形象描述:
不需要的话,就算了吧.
Balk的含义:退缩不前.
2. 模式描述:
当现在不适合进行某个操作,或者没有必要进行某个操作时,就直接放弃进行这个操作而回去,这 就是Balking Pattern.
Balking Pattern中, 有一个具有状态的对象,而这个对象只想再自己的状态合适时,才进行线程目的操作,当状态不合适时,就不进行目的操作了.以"警戒条件"来表示对象的合适状态,并在目的操作之前,测试现在使用满足警戒条件,只有在警戒条件满足时,才会进行目的操作,而警戒条件不满足时,就会直接从方法中退出.
Java语言中,使用if语句来测试警戒条件.balk的时候,可以使用return方法退出,或者使用throw抛出异常.警戒条件的测试,要使用synchronized放进临界区内.
3. 模式参与者:
3.1 被警戒的对象(GuardedObject) :
该参与者是一个拥有被警戒(guardMethod)的方法的类.当线程执行guardMethod时,只 要满足警戒条件就会执行实力的操作,但警戒条件不成立时,就不知行实例操作,而直接退出.
警戒条件的成立与否,会随着GuardedObject的状态变化.该参与者可能还具有更改实例状 态的方法.
4. 范例程序:
设计一个简单的文件内容编辑器,当文件内容发生变化的时候自动保存文件.
<1>被警戒对象-FileData, 该类表示一个文件的内容.
package com.quf.study.thread.balk;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.io.Writer;
import org.apache.log4j.Logger;
/**
* <strong>Title : FileData<br>
* </strong> <strong>Description : </strong>文件数据实体类,该类保存某个文件的内容.<br>
* <strong>Create on : 2008-4-25<br>
* </strong>
* <p>
* <strong>Copyright (C) QUF Software Co.,Ltd.<br>
* </strong>
* <p>
*
* @author renxin renxin777@126.com<br>
* @version <strong>Java Thread Design Pattern Study</strong><br>
* <br>
* <strong>修改历史:</strong><br>
* 修改人 修改日期 修改描述<br>
* -------------------------------------------<br>
* <br>
* <br>
*/
public class FileData implements Serializable {
/**
* <code>serialVersionUID</code>-序列号
*/
private static final long serialVersionUID = 4095666244812656901L;
/**
* <code>s_logger</code>-日志记录类.
*/
private static Logger s_logger = Logger.getLogger(FileData.class);
/**
* <code>m_filename</code>-文件名称.
*/
private final String m_filename;
/**
* <code>m_fileContent</code>-文件的内容.
*/
private String m_fileContent;
/**
* <code>m_change</code>-文件内容是否已经被修改,true-表示已经被修改,false-表示未被修改.
*/
private boolean m_change;
/**
* 构造函数
*/
public FileData(String filename, String fileContent) {
// TODO Auto-generated constructor stub
this.m_filename = filename;
this.m_fileContent = fileContent;
this.m_change = false;
}
/**
* 改变文件的内容.
*
* @param fileContent -
* 新的文件内容.
*/
public synchronized void change(String fileContent) {
this.m_fileContent = fileContent;
this.m_change = true;
}
/**
* 保存文件内容.
*
* @throws IOException
*/
public synchronized void save() throws IOException {
// 1. 判断文件是否已经被修改.
if (!this.m_change) {
return;
}
// 2. 保存文件内容.
this.doSave();
// 3. 将是否已经修改的标志设置为false.
this.m_change = false;
}
/**
* 保存文件内容.
*
* @throws IOException
*/
private void doSave() throws IOException {
if (s_logger.isDebugEnabled()) {
s_logger.debug(Thread.currentThread().getName().concat(
"calls doSave() ,fileContent:").concat(this.m_fileContent));
}
// System.out.println(Thread.currentThread().getName().concat(
// "calls doSave() ,fileContent:").concat(this.m_fileContent));
Writer t_fileWriter = null;
try {
t_fileWriter = new FileWriter(this.m_filename);
t_fileWriter.write(this.m_fileContent);
t_fileWriter.close();
} catch (IOException e) {
// TODO: handle exception
throw e;
} finally {
if (null != t_fileWriter) {
try {
t_fileWriter.close();
} catch (Exception e) {
// TODO: handle exception
}
}
}
}
}// END CLASS OF FileData.
<2>SaveFileThread-定期检查文件内容是否改变,并且进行保存的线程类:
package com.quf.study.thread.balk;
import java.io.IOException;
import org.apache.log4j.Logger;
/**
* <strong>Title : SaveFileThread<br></strong>
* <strong>Description : </strong>定期保存文件的线程类.<br>
* <strong>Create on : 2008-4-25<br></strong>
* <p>
* <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
* <p>
* @author renxin renxin777@126.com<br>
* @version <strong>Java Thread Design Pattern Study</strong><br>
* <br>
* <strong>修改历史:</strong><br>
* 修改人 修改日期 修改描述<br>
* -------------------------------------------<br>
* <br>
* <br>
*/
public class SaveFileThread extends Thread {
/**
* <code>s_looger</code>-日志记录类.
*/
private static Logger s_looger = Logger.getLogger(SaveFileThread.class);
/**
* <code>m_fileData</code>-文件数据类.
*/
private FileData m_fileData;
/**
* 构造函数
* @param name
* @param fileData
*/
public SaveFileThread(String name,FileData fileData) {
super(name);
// TODO Auto-generated constructor stub
this.m_fileData = fileData;
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
public void run(){
try {
while( true ) {
this.m_fileData.save();
Thread.sleep(1000);
}
} catch (IOException ioe) {
// TODO: handle exception
s_looger.error(ioe.getMessage(),ioe);
} catch (InterruptedException e) {
// TODO: handle exception
s_looger.error(e.getMessage(),e);
}
}
}//END CLASS OF SaveFileThread.
<3> ChangeFileThread - 定期改变文件内容的线程类:
package com.quf.study.thread.balk;
import java.io.IOException;
import java.util.Random;
import org.apache.log4j.Logger;
/**
* <strong>Title : ChangeFileThread<br></strong>
* <strong>Description : </strong>定时修改文件的线程类.<br>
* <strong>Create on : 2008-4-25<br></strong>
* <p>
* <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
* <p>
* @author renxin renxin777@126.com<br>
* @version <strong>Java Thread Design Pattern Study</strong><br>
* <br>
* <strong>修改历史:</strong><br>
* 修改人 修改日期 修改描述<br>
* -------------------------------------------<br>
* <br>
* <br>
*/
public final class ChangeFileThread extends Thread {
/**
* <code>s_logger</code>-日志记录类.
*/
private static Logger s_logger = Logger.getLogger(ChangeFileThread.class);
/**
* <code>m_fileData</code>-文件数据类.
*/
private FileData m_fileData;
/**
* <code>m_random</code>-随机值对象.
*/
private Random m_random = new Random();
/**
* 构造函数
* @param name - 线程名称.
* @param fileData - 文件内容对象.
*/
public ChangeFileThread(String name,FileData fileData){
super(name);
this.m_fileData = fileData;
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
public void run() {
try {
for ( int i = 0 ; true ; i++ ) {
//改变文件内容.
this.m_fileData.change("Nc."+i);
//模拟程序去做其他的事情.
Thread.sleep(this.m_random.nextInt(1000));
//显示的主动区保存文件.
this.m_fileData.save();
}
} catch (IOException e) {
s_logger.error(e.getMessage(), e);
} catch (InterruptedException e) {
s_logger.error(e.getMessage(), e);
}
}
}//END CLASS OF ChangeFileThread.
<4>BalkDPTest - 测试类:
package com.quf.study.thread.balk;
/**
* <strong>Title : BalkDPTest<br></strong>
* <strong>Description : </strong>Balk模式的测试类.<br>
* <strong>Create on : 2008-4-25<br></strong>
* <p>
* <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
* <p>
* @author renxin renxin777@126.com<br>
* @version <strong>Java Thread Design Pattern Study</strong><br>
* <br>
* <strong>修改历史:</strong><br>
* 修改人 修改日期 修改描述<br>
* -------------------------------------------<br>
* <br>
* <br>
*/
public class BalkDPTest {
/**
* 构造函数
*/
public BalkDPTest() {
// TODO Auto-generated constructor stub
}
/**
* 方法描述
* @param args
*/
public static void main(String[] args){
FileData t_fileData = new FileData("data.txt","(empty)");
//创建两个线程.
ChangeFileThread t_changeFileThread = new ChangeFileThread("changeFileThread",t_fileData);
SaveFileThread t_saveFileThread = new SaveFileThread("saveFileThread",t_fileData);
//启动两个线程.
t_changeFileThread.start();
t_saveFileThread.start();
}
}//END CLASS OF BalkDPTest.
5. 使用的场景:
5.1 不需要刻意去执行的时候.
5.2 不想等待警戒条件成立时.
5.3 警戒条件只有第一次成立时.
6. 表达balk结果的方式:
6.1 忽略balk的发生:
不通知调用端balk的发生.
6.2 以返回值表达balk的发生:
以boolean类型的返回值表示balk的发生.
6.3 以异常表达balk的发生.
7. 相关知识:
7.1 wait方法的结束时机:
<1> 当notify方法执行时:
当调用obj上的notify方法的时候,线程被唤醒,但当等待区内有多个线程的时候,只有一个线程会被唤醒.
<2> 当notifyAll方法执行时:
调用obj的notifyAll方法时,实例等待区那的所有线程都将被环境.
无论时notify还是notifyAll唤醒的线程,还是都要重新获取实例的锁.
<3> 当interrupted执行时.
对该线程调用interrupted方法时.
被interrupted时,等待区内的线程会重新获取对象的锁,并抛出InterruptedException异常.
notify,notifyAll两个方法是对实例的调用,而interrupted是对具体线程的调用.
<4> 发生timeout的时候.
不需要的话,就算了吧.
Balk的含义:退缩不前.
2. 模式描述:
当现在不适合进行某个操作,或者没有必要进行某个操作时,就直接放弃进行这个操作而回去,这 就是Balking Pattern.
Balking Pattern中, 有一个具有状态的对象,而这个对象只想再自己的状态合适时,才进行线程目的操作,当状态不合适时,就不进行目的操作了.以"警戒条件"来表示对象的合适状态,并在目的操作之前,测试现在使用满足警戒条件,只有在警戒条件满足时,才会进行目的操作,而警戒条件不满足时,就会直接从方法中退出.
Java语言中,使用if语句来测试警戒条件.balk的时候,可以使用return方法退出,或者使用throw抛出异常.警戒条件的测试,要使用synchronized放进临界区内.
3. 模式参与者:
3.1 被警戒的对象(GuardedObject) :
该参与者是一个拥有被警戒(guardMethod)的方法的类.当线程执行guardMethod时,只 要满足警戒条件就会执行实力的操作,但警戒条件不成立时,就不知行实例操作,而直接退出.
警戒条件的成立与否,会随着GuardedObject的状态变化.该参与者可能还具有更改实例状 态的方法.
4. 范例程序:
设计一个简单的文件内容编辑器,当文件内容发生变化的时候自动保存文件.
<1>被警戒对象-FileData, 该类表示一个文件的内容.
package com.quf.study.thread.balk;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.io.Writer;
import org.apache.log4j.Logger;
/**
* <strong>Title : FileData<br>
* </strong> <strong>Description : </strong>文件数据实体类,该类保存某个文件的内容.<br>
* <strong>Create on : 2008-4-25<br>
* </strong>
* <p>
* <strong>Copyright (C) QUF Software Co.,Ltd.<br>
* </strong>
* <p>
*
* @author renxin renxin777@126.com<br>
* @version <strong>Java Thread Design Pattern Study</strong><br>
* <br>
* <strong>修改历史:</strong><br>
* 修改人 修改日期 修改描述<br>
* -------------------------------------------<br>
* <br>
* <br>
*/
public class FileData implements Serializable {
/**
* <code>serialVersionUID</code>-序列号
*/
private static final long serialVersionUID = 4095666244812656901L;
/**
* <code>s_logger</code>-日志记录类.
*/
private static Logger s_logger = Logger.getLogger(FileData.class);
/**
* <code>m_filename</code>-文件名称.
*/
private final String m_filename;
/**
* <code>m_fileContent</code>-文件的内容.
*/
private String m_fileContent;
/**
* <code>m_change</code>-文件内容是否已经被修改,true-表示已经被修改,false-表示未被修改.
*/
private boolean m_change;
/**
* 构造函数
*/
public FileData(String filename, String fileContent) {
// TODO Auto-generated constructor stub
this.m_filename = filename;
this.m_fileContent = fileContent;
this.m_change = false;
}
/**
* 改变文件的内容.
*
* @param fileContent -
* 新的文件内容.
*/
public synchronized void change(String fileContent) {
this.m_fileContent = fileContent;
this.m_change = true;
}
/**
* 保存文件内容.
*
* @throws IOException
*/
public synchronized void save() throws IOException {
// 1. 判断文件是否已经被修改.
if (!this.m_change) {
return;
}
// 2. 保存文件内容.
this.doSave();
// 3. 将是否已经修改的标志设置为false.
this.m_change = false;
}
/**
* 保存文件内容.
*
* @throws IOException
*/
private void doSave() throws IOException {
if (s_logger.isDebugEnabled()) {
s_logger.debug(Thread.currentThread().getName().concat(
"calls doSave() ,fileContent:").concat(this.m_fileContent));
}
// System.out.println(Thread.currentThread().getName().concat(
// "calls doSave() ,fileContent:").concat(this.m_fileContent));
Writer t_fileWriter = null;
try {
t_fileWriter = new FileWriter(this.m_filename);
t_fileWriter.write(this.m_fileContent);
t_fileWriter.close();
} catch (IOException e) {
// TODO: handle exception
throw e;
} finally {
if (null != t_fileWriter) {
try {
t_fileWriter.close();
} catch (Exception e) {
// TODO: handle exception
}
}
}
}
}// END CLASS OF FileData.
<2>SaveFileThread-定期检查文件内容是否改变,并且进行保存的线程类:
package com.quf.study.thread.balk;
import java.io.IOException;
import org.apache.log4j.Logger;
/**
* <strong>Title : SaveFileThread<br></strong>
* <strong>Description : </strong>定期保存文件的线程类.<br>
* <strong>Create on : 2008-4-25<br></strong>
* <p>
* <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
* <p>
* @author renxin renxin777@126.com<br>
* @version <strong>Java Thread Design Pattern Study</strong><br>
* <br>
* <strong>修改历史:</strong><br>
* 修改人 修改日期 修改描述<br>
* -------------------------------------------<br>
* <br>
* <br>
*/
public class SaveFileThread extends Thread {
/**
* <code>s_looger</code>-日志记录类.
*/
private static Logger s_looger = Logger.getLogger(SaveFileThread.class);
/**
* <code>m_fileData</code>-文件数据类.
*/
private FileData m_fileData;
/**
* 构造函数
* @param name
* @param fileData
*/
public SaveFileThread(String name,FileData fileData) {
super(name);
// TODO Auto-generated constructor stub
this.m_fileData = fileData;
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
public void run(){
try {
while( true ) {
this.m_fileData.save();
Thread.sleep(1000);
}
} catch (IOException ioe) {
// TODO: handle exception
s_looger.error(ioe.getMessage(),ioe);
} catch (InterruptedException e) {
// TODO: handle exception
s_looger.error(e.getMessage(),e);
}
}
}//END CLASS OF SaveFileThread.
<3> ChangeFileThread - 定期改变文件内容的线程类:
package com.quf.study.thread.balk;
import java.io.IOException;
import java.util.Random;
import org.apache.log4j.Logger;
/**
* <strong>Title : ChangeFileThread<br></strong>
* <strong>Description : </strong>定时修改文件的线程类.<br>
* <strong>Create on : 2008-4-25<br></strong>
* <p>
* <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
* <p>
* @author renxin renxin777@126.com<br>
* @version <strong>Java Thread Design Pattern Study</strong><br>
* <br>
* <strong>修改历史:</strong><br>
* 修改人 修改日期 修改描述<br>
* -------------------------------------------<br>
* <br>
* <br>
*/
public final class ChangeFileThread extends Thread {
/**
* <code>s_logger</code>-日志记录类.
*/
private static Logger s_logger = Logger.getLogger(ChangeFileThread.class);
/**
* <code>m_fileData</code>-文件数据类.
*/
private FileData m_fileData;
/**
* <code>m_random</code>-随机值对象.
*/
private Random m_random = new Random();
/**
* 构造函数
* @param name - 线程名称.
* @param fileData - 文件内容对象.
*/
public ChangeFileThread(String name,FileData fileData){
super(name);
this.m_fileData = fileData;
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
public void run() {
try {
for ( int i = 0 ; true ; i++ ) {
//改变文件内容.
this.m_fileData.change("Nc."+i);
//模拟程序去做其他的事情.
Thread.sleep(this.m_random.nextInt(1000));
//显示的主动区保存文件.
this.m_fileData.save();
}
} catch (IOException e) {
s_logger.error(e.getMessage(), e);
} catch (InterruptedException e) {
s_logger.error(e.getMessage(), e);
}
}
}//END CLASS OF ChangeFileThread.
<4>BalkDPTest - 测试类:
package com.quf.study.thread.balk;
/**
* <strong>Title : BalkDPTest<br></strong>
* <strong>Description : </strong>Balk模式的测试类.<br>
* <strong>Create on : 2008-4-25<br></strong>
* <p>
* <strong>Copyright (C) QUF Software Co.,Ltd.<br></strong>
* <p>
* @author renxin renxin777@126.com<br>
* @version <strong>Java Thread Design Pattern Study</strong><br>
* <br>
* <strong>修改历史:</strong><br>
* 修改人 修改日期 修改描述<br>
* -------------------------------------------<br>
* <br>
* <br>
*/
public class BalkDPTest {
/**
* 构造函数
*/
public BalkDPTest() {
// TODO Auto-generated constructor stub
}
/**
* 方法描述
* @param args
*/
public static void main(String[] args){
FileData t_fileData = new FileData("data.txt","(empty)");
//创建两个线程.
ChangeFileThread t_changeFileThread = new ChangeFileThread("changeFileThread",t_fileData);
SaveFileThread t_saveFileThread = new SaveFileThread("saveFileThread",t_fileData);
//启动两个线程.
t_changeFileThread.start();
t_saveFileThread.start();
}
}//END CLASS OF BalkDPTest.
5. 使用的场景:
5.1 不需要刻意去执行的时候.
5.2 不想等待警戒条件成立时.
5.3 警戒条件只有第一次成立时.
6. 表达balk结果的方式:
6.1 忽略balk的发生:
不通知调用端balk的发生.
6.2 以返回值表达balk的发生:
以boolean类型的返回值表示balk的发生.
6.3 以异常表达balk的发生.
7. 相关知识:
7.1 wait方法的结束时机:
<1> 当notify方法执行时:
当调用obj上的notify方法的时候,线程被唤醒,但当等待区内有多个线程的时候,只有一个线程会被唤醒.
<2> 当notifyAll方法执行时:
调用obj的notifyAll方法时,实例等待区那的所有线程都将被环境.
无论时notify还是notifyAll唤醒的线程,还是都要重新获取实例的锁.
<3> 当interrupted执行时.
对该线程调用interrupted方法时.
被interrupted时,等待区内的线程会重新获取对象的锁,并抛出InterruptedException异常.
notify,notifyAll两个方法是对实例的调用,而interrupted是对具体线程的调用.
<4> 发生timeout的时候.