原文案例来自于《java 高并发编程详解》
Balking 模式释义
比如我们在用word 编写文档的时候,每次文字编辑都代表着文档的状态发生了改变,除了我们手动使用ctrl+s保存文档以外,word还可以设置自动保存。如果word自动保存文档的线程正在准备执行保存动作的时候,恰好我们手动进行了保存动作,那么自动保存文档的线程将会放弃本次保存动作---摘自《java 高并发编程详解》
下面用代码盘它
使用代码翻译之前,先分析这个案例有哪些角色:
- 文档工作的具体类,这个类需要包含文档编写、保存的工作
- 监听用户输入的内容,用户有内容输入时执行文档编写工作,同时提供手动保存的接口,很明显使用线程扮演这个角色非常合适。需要注意的是,当监听到用户没有输入内容时应阻塞起来,防止占用cpu资源。
- 自动保存用户输入的内容,如果已经保存过则跳过。同样的使用线程来扮演较为合适。同样需要注意的是,这个线程没有手动停止(类似在word中取消自动保存)或者发生中断退出 应该一直在运行。对于文档已经保存过了则直接将自己阻塞起来,防止占用cpu资源。
- 原文的代码并未解决线程在没有内容输入时已经保存过 线程依然占用cpu资源的情况。本案例会尝试解决这个问题
文档工具类
package com.example.liuxiaobing.statemodel.mutil_thread.balking;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Create By 刘胡来
* Create Date 2020/4/25
* Sensetime@Copyright
* Des:
*/
public class Document {
private boolean changed = false;
private List<String> content = new ArrayList<>();
private FileWriter writer;
private AutoSaveThread autoSaveThread;
public Document(String documentPath,String documentName) throws IOException {
this.writer = new FileWriter(new File(documentPath,documentName),true);
autoSaveThread = new AutoSaveThread(this);
autoSaveThread.start();
}
/**
* 有文本添加时,将之前阻塞的线程唤醒
* @param content
*/
public void edit(String content){
synchronized (this){
this.content.add(content);
this.changed = true;
notifyAll();
}
}
/**
* 停掉自动保存的线程
* @throws IOException
*/
public void close() throws IOException {
autoSaveThread.interrupt();
writer.close();
}
/**
* 保存文档
* @throws IOException
* @throws InterruptedException
*/
public void save() throws IOException, InterruptedException {
synchronized (this){
/**
* 对于已经保存过的 就阻塞当前线程
*/
while(content.isEmpty()){
System.out.println("55-----------curent "+Thread.currentThread().getName() +" blocked:");
wait();
}
if(!changed){
return;
}
for(String cacheLine:content){
// this.writer.write(cacheLine);
// this.writer.write("\r\n");
System.out.println("51-------exe save action :"+cacheLine);
}
this.writer.flush();
this.changed = false;
this.content.clear();
}
}
}
监听用户输入内容的线程
package com.example.liuxiaobing.statemodel.mutil_thread.balking;
import android.text.TextUtils;
import java.io.IOException;
import java.util.Scanner;
/**
* Create By 刘胡来
* Create Date 2020/4/25
* Sensetime@Copyright
* Des: 文档编辑线程
*/
public class DocumentEditThread extends Thread {
private String documentPath;
private String documentName;
private Document document;
public DocumentEditThread(String documentPath,String documentName){
super("DocumentEditThread");
this.documentPath = documentPath;
this.documentName = documentName;
try {
document = new Document(documentPath,documentName);
} catch (IOException e) {
e.printStackTrace();
}
}
public void buildContent(String content){
if(!TextUtils.isEmpty(content)){
document.edit(content);
System.out.println("56------------add text:"+content);
}
}
public void close(){
try {
interrupt();
document.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
super.run();
int times = 0;
try {
while (!interrupted()){
if(times == 20){
document.save();//此处模拟手动保存
times = 0;
}
times ++;
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
自动保存文档的线程
package com.example.liuxiaobing.statemodel.mutil_thread.balking;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* Create By 刘胡来
* Create Date 2020/4/25
* Sensetime@Copyright
* Des: 自动保存数据的任务线程,核心点在于有任务来了之后就保存,如果已经保存了就不再保存
*/
public class AutoSaveThread extends Thread {
private Document document;
public AutoSaveThread(Document document){
super("Document AutoSaveThread");
this.document = document;
}
@Override
public void run() {
super.run();
while(!interrupted()){
try {
document.save();
TimeUnit.SECONDS.sleep(10);
} catch (IOException e) {
e.printStackTrace();
break;
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
测试用例 借用android
性能参数