多线程模式-Balking模式

本文通过一个Word自动保存与手动保存的示例,介绍了Balking设计模式,即线程在发现其他线程已进行相同工作时选择放弃。在示例中,`AutoSaveThread`负责自动保存文档,`Document`类用于编辑和保存,`DocumentEditThread`用于模拟用户编辑。当手动保存后,自动保存线程会检测到变化并放弃保存,有效防止了资源浪费。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多个线程监控某个共享变量,A 线程监控到共享变量发生变化后即将触发某个动作,但 是此时发现有另外一个线程 B 已经针对该变量的变化开始了行动,因此 A 便放弃了准备 开始的工作,我们把这样的线程间交互称为 Balking(犹豫)设计模式。其实这样的场景 在生活中很常见,比如你去饭店吃饭,吃到途中想要再点一个小菜,于是你举起手示意服务 员,其中一个服务员看到了你举手正准备走过来的时候,发现距离你比较近的服务员已经准 备要受理你的请求于是中途放弃了。

我们举个实例:我们在用 word 编写文档的时候,每次的文字编辑都代表着文档的状态发生了 改变,除了我们可以使用 ctrl+s 快捷键手动保存以外,word 软件本身也会定期触发自动 保存,如果 word 自动保存文档的线程在准备执行保存动作的时候,恰巧我们进行了主动保 存,那么自动保存文档的线程将会放弃此次的保存动作。

接下来代码实现这个案例

这里我们分为三个类分别是:自动保存线程类(AutoSaveThread)、操作文档类(Document)、手动使用文档线程类(DocumentEditThread),在创建一个document对象时会启动AutoSaveThread线程帮助自动保存文档,这里我们就需要设置一个标记来记录文档是否已经改变,在save()方法当中主要依靠这个标记来决定当前线程是否要保存文档。自动保存设置为每5s保存一次。当我们编辑文档直接手动保存,来看自动保存是否执行。

自动保存线程类(AutoSaveThread)

public class AutoSaveThread extends Thread {
    private Document document;

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

    @Override
    public void run() {
       while (true){
           //每隔5s 自动保存一次
           try {
               this.document.save();
               TimeUnit.SECONDS.sleep(5);
           } catch (IOException | InterruptedException e) {
               e.printStackTrace();
           }
       }
    }
}

操作文档类(Document)

public class Document {
    
    //标记文档是否发生改变
    private boolean change = false;
    //写对象
    private final FileWriter fileWriter;
    //内容缓存区
    private List<String> contents = new ArrayList<>();
    //自动保存线程对象
    private static AutoSaveThread autoSaveThread;

    //构造函数 需要传入文档的保存路径和文档名称
    public Document(String documentPath,String documentName) throws IOException {
        this.fileWriter = new FileWriter(new File(documentPath,documentName));
    }
    //创建Document 对象方法 顺便启动自动保存对象
    public static Document create(String documentPath,String documentName) throws IOException {
        Document document = new Document(documentPath, documentName);
        //启动自动保存对象
        autoSaveThread = new AutoSaveThread(document);
        autoSaveThread.start();
        return document;
    }

    //编辑方法 将输入的字符全部放入到缓存区里
    public synchronized void edit(String content){
        this.contents.add(content);
        //文档编辑完,文档发生改变
        this.change = true;
    }
    //文档保存 将缓存区的的数据全部写入到文档中
    public synchronized void save() throws IOException {
        //判断文档是否修改 (没有修改并不需要保存)
        if (!change)
            return;
        for (String cache:contents){
            this.fileWriter.write(cache);
            this.fileWriter.write("\r\n");
        }
        this.fileWriter.flush();
        System.out.println(Thread.currentThread().getName()+"保存成功,保存的内容为"+this.contents);
        this.contents.clear();
        //修改标记
        this.change = false;
    }

    //关闭文档方法  中断自动保存线程,关闭输出流
    public void close() throws IOException {
        autoSaveThread.interrupt();
        fileWriter.close();
    }
}

手动使用文档线程类(DocumentEditThread)

public class DocumentEditThread extends Thread {

    private final Scanner scanner ;
    private String documentPath;
    private String documentName;
    public DocumentEditThread(String documentPath,String documentName ){
        super("DocumentEditThread");
        this.scanner = new Scanner(System.in);
        this.documentPath = documentPath;
        this.documentName = documentName;
    }

    @Override
    public void run() {
        try {
            //创建文档
            Document document = Document.create(documentPath, documentName);
            while (true){
                //获取用户键盘输入
                String text = this.scanner.next();
                //当输入 /exit 退出文档
                if("/exit".equals(text)){
                    document.close();
                    break;
                }else if ("/save".equals(text)){ //输入 /save 手动保存
                    document.save();
                }else {
                    //编辑文档
                    document.edit(text);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果:当手动保存后自动保存不会执行

a
AutoSaveThread保存成功,保存的内容为[a]
b
v
f
AutoSaveThread保存成功,保存的内容为[b, v, f]
q
AutoSaveThread保存成功,保存的内容为[q]
w
e
r
tt
y
uAutoSaveThread保存成功,保存的内容为[w, e, r, tt, y]
a
AutoSaveThread保存成功,保存的内容为[a]
a
/save
DocumentEditThread保存成功,保存的内容为[a]
/exit

结论:想必大家已经清楚了 Balking 设计模式要解决的问题了吧, 就是某个线程因为发现其他线程正在进行相同的工作而放弃即将开始的任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值