Java多线程设计模式-学习笔记-Balking模式.

来源:互联网 发布:威客网络兼职怎么赚钱 编辑:程序博客网 时间:2024/06/05 06:05
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的时候.
 
原创粉丝点击