Balking设计模式

什么是Balking设计模式?

     多个线程监控某个共享变量,A线程监控到共享变量发生变化后即将触发某个动作,但是此时发现有另外一个线程B已经针对该变量的变化开始了行动,因此A便放弃了准备开始的动作,我们把这样的线程间交互成为Balking(犹豫)设计模式。其实这样的场景在生活中很常见,比如你去饭店吃饭,吃到途中想要再点一个小菜,于是你举起手示意服务员,其中一个服务员看到了你举手正准备走过来的时候,发现距离你
比较近的服务员已经准备要受理你的请求于是中途放弃了。
    再比如,我们在用word编写文档的时候,每次的文字编辑都代表着文档的状态发生了改变,除了我们可以使用
ctrl+s快捷键手动保存以外,word软件本身也会定期触发自动保存,如果word自动保存文档的线程在准备执行保存
动作的时候,恰巧我们进行了主动保存,那么自动保存文档的线程将会放弃此次的保存动作。
    看了以上两个例子的说明,想必大家已经清楚了Balking设计模式要解决的问题了吧,简短的说就是某个线程因为
发现其他线程正在进行相同的工作而放弃即将开始的任务。在本章中,我们将通过模拟word文档自动保存与手动保存的功能讲解
Balking模式的设计与应用。

Balking模式之文档编辑

Document:

package MutilThreadModel.BalkingModel;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import static java.lang.Thread.currentThread;

/**
 * Created by JYM on 2019/1/14
 * 在Document中有两个主要方法save和edit分别用于保存文档和编辑文档。
 * */

//代表正在编辑的文档类
public class Document
{
    //如果文档发生改变,changed会被设置为true
    private boolean changed = false;

    //一次需要保存的内容,可以将其理解为内容缓存
    private List<String> content = new ArrayList<>();

    private final FileWriter writer;

    //自动保存文档的线程
    private static AutoSaveThread autoSaveThread;

    //构造函数需要传入文档保存的路径和文档名称
    private Document(String documentPath,String documentName) throws IOException
    {
        this.writer = new FileWriter(new File(documentPath,documentName),true);
    }

    //静态方法,主要用于创建文档,顺便启动自动保存文档的线程
    public static Document create(String documentPath,String documentName) throws IOException
    {
        Document document = new Document(documentPath,documentName);
        autoSaveThread = new AutoSaveThread(document);
        autoSaveThread.start();
        return document;
    }

    //文档的编辑,其实就是往content队列中提交字符串
    public void edit(String content)
    {
        synchronized (this)
        {
            this.content.add(content);
            //文档改变,changed会变为true
            this.changed = true;
        }
    }

    //文档关闭的时候首先中断自动保存线程,然后关闭writer释放资源
    public void close() throws IOException
    {
        autoSaveThread.interrupt();
        writer.close();
    }

    //save方法用于为外部显式进行文档保存
    public void save() throws IOException
    {
        synchronized (this)
        {
            //balking,如果文档已经被保存了,则直接返回
            if (!changed)
            {
                return;
            }
            System.out.println(currentThread()+" execute the save action");
            //将内容写入文档中
            for (String cacheLine : content)
            {
                this.writer.write(cacheLine);
                this.writer.write("\r\n");
            }

            this.writer.flush();
            //将changed修改为false,表明此刻再没有新的内容编辑
            this.changed = false;
            this.content.clear();
        }
    }
}

/**在上面的代码中:
 * 1>edit方法和save方法进行方法同步,其目的在于防止当文档在保存的过程中如果遇到新的内容被编辑时
 * 引起的共享资源冲突问题。
 * 2>changed在默认的情况下为false,当有新的内容被编辑的时候将被修改为true。
 * 3>在进行文档保存的时候,首先查看changed是否为true,如果文档发生过编辑则在文档中保存新的内容,
 * 否则就会放弃此次保存动作,changed是balking pattern关注的状态,当changed为true的时候就想远处的
 * 服务员看到客户的请求被另外一个服务员接管了一样,于是放弃了任务的执行。
 * 4>在创建Document的时候,顺便还会启动自动保存文档的线程,该线程的主要目的在于在固定时间里执行
 * 一次文档保存动作。
 * */

AutoSaveThread

package MutilThreadModel.BalkingModel;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * Created by JYM on 2019/1/14
 * 下面这个类函数实现的是文档的自动保存.
 * AutoSaveThread比较简单,其主要的工作就是每个一秒的时间调用一次document的save方法。
 * */

public class AutoSaveThread extends Thread
{
    private final Document document;

    public AutoSaveThread(Document document)
    {
        super("DocumentAutoSaveThread");
        this.document = document;
    }

    @Override
    public void run()
    {
        while (true)
        {
            try
            {
                //每隔一秒自动保存一次文档
                document.save();
                TimeUnit.SECONDS.sleep(1);
            }catch (IOException | InterruptedException e)
            {
                break;
            }
        }
    }
}

DocumentEditThread:

package MutilThreadModel.BalkingModel;

import java.io.IOException;
import java.util.Scanner;

/**
 * Created by JYM on 2019/1/14
 * DocumentEditThread线程则类似于主动编辑文档的作者,在DocumentEditThreadzhong中除了对文档进行修改编辑之外,还是同时按下Ctrl+S
 * 组合键(调用save方法)主动保存。
 * */

//该线程代表的是主动进行文件编辑的线程,为了增加交互性,我们使用了Scanner
public class DocumentEditThread extends Thread
{
    private final String documentPath;

    private final String documentName;

    private final Scanner scanner = new Scanner(System.in);

    public DocumentEditThread(String documentPath,String documentName)
    {
        super("DocumentEditThread");
        this.documentPath = documentPath;
        this.documentName = documentName;
    }

    @Override
    public void run() {
        int times = 0;

        try {
            Document document = Document.create(documentPath,documentName);   //创建编辑文档
            while (true)
            {
                //获取用户的键盘输入
                String text = scanner.next();
                if ("quit".equals(text))
                {
                    document.close();
                    break;
                }
                //将内容编辑到document中
                document.edit(text);
                if (times==5)
                {
                    //用户在输入了5次之后进行文档保存
                    document.save();
                    times=0;
                }
                times++;
            }
        }catch (IOException e)
        {
            throw new RuntimeException(e);
        }
    }
}
/**
 * DocumentEditThread类代表了主动编辑文档的线程,在该线程中,我们使用scanner交互的方式,每一次对文档的修改
 * 都不可能直接保存(Ctrl+S),因此在程序中约定了五次以后主动执行保存动作,当输入quit时,表示要退出此次文档编辑。
 * */

测试:

package MutilThreadModel.BalkingModel;

/**
 * Created by JYM on 2019/1/14
 *
 * 测试程序:
 * */

public class BalkingTest
{
    public static void main(String[] args)
    {
        new DocumentEditThread("G:\\","balking.txt").start();
    }
}

/**
 * Balking模式在日常的开发中很常见,比如在系统资源的加载或者某些数据的初始化时,
 * 在整个系统中声明中期中资源可能只被加载一次,我们就可以采用balking模式加以解决,
 * 代码如下:
 * public synchronized Map<String, Resource> load()
 * {
 *     //balking
 *     if(load)
 *     {
 *         return resourceMap;
 *     }else
 *     {
 *         //do the resource load task;
 *         //....
 *         this.loaded = true;
 *         return resoureMap;
 *     }
 * }
 * */

猜你喜欢

转载自blog.csdn.net/leying521/article/details/86478275