如何保证单例式或者说一个方法的执行过后,就不会有另外的方法去再次执行了呢,简化的说,就是一个多线程状态下,如何保证一个if
且让这个if 状态是线程安全的
那么,对于一个状态条件的安全性,可以使用一个即为简单的解决方案,就是进行加互斥锁,加互斥锁,下面一个示例代码 可以简单的实现这个解决方案
//自动存盘操作
void autoSave(){
synchronized(this){
if (!changed) {
return;
}
changed = false;
}
//执行存盘操作
//省略且实现
this.execSave();
}
//编辑操作
void edit(){
//省略编辑逻辑
synchronized(this){
changed = true;
}
}
那么针对一个多线程下的if,被总结为了一个设计模式,叫做Balking设计模式
这个设计模式中关于条件变量的修改,将其放置到了一个线程安全的方法之中
将条件变量封装为了一个函数,减少了线程同步消耗
boolean changed=false;
//自动存盘操作
void autoSave(){
synchronized(this){
if (!changed) {
return;
}
changed = false;
}
//执行存盘操作
//省略且实现
this.execSave();
}
//编辑操作
void edit(){
//省略编辑逻辑
change();
}
//改变状态
void change(){
synchronized(this){
changed = true;
}
}
这样就能最小化的将同步线程的消耗降低
接下来可以考虑使用volatile实现Balking
但是使用volatile需要对原子性没有要求,可以保证可见性
那一个场景距离,假设RPC框架可能出现宕机状况,那么需要针对这种极端的情况进行备份管理,在一定情况的时候进行自动保存一次,保存后将是否修改的值置为false
//路由表信息
public class RouterTable {
//Key:接口名
//Value:路由集合
ConcurrentHashMap<String, CopyOnWriteArraySet<Router>> rt = new ConcurrentHashMap<>();
//路由表是否发生变化
volatile boolean changed;
//将路由表写入本地文件的线程池
ScheduledExecutorService ses= Executors.newSingleThreadScheduledExecutor();
//启动定时任务
//将变更后的路由表写入本地文件
public void startLocalSaver(){
ses.scheduleWithFixedDelay(()->{
autoSave();
}, 1, 1, MINUTES);
}
//保存路由表到本地文件
void autoSave() {
if (!changed) {
return;
}
changed = false;
//将路由表写入本地文件
//省略其方法实现
this.save2Local();
}
//删除路由
public void remove(Router router) {
Set<Router> set=rt.get(router.iface);
if (set != null) {
set.remove(router);
//路由表已发生变化
changed = true;
}
}
//增加路由
public void add(Router router) {
Set<Router> set = rt.computeIfAbsent(
route.iface, r ->
new CopyOnWriteArraySet<>());
set.add(router);
//路由表已发生变化
changed = true;
}
}
那么接下里还有就是其契合单例模式,因为单例模式本质上也是单词初始化,可以使用Balking模式来实现线程安全的单例模式
就是在获取到实例之前进行加锁,保证其获取的线程同步性
如果需要进行优化,可以考虑在锁的外面进行一次判断,如果为null在进行获取到锁
class Singleton {
private static volatile
Singleton singleton;
//构造方法私有化
private Singleton() {
}
//获取实例(单例)
public static Singleton getInstance() {
//第一次检查
if (singleton == null) {
synchronize {
Singleton.class){
//获取锁后二次检查
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
}
Balking的经典实现方式是互斥锁,Synchronized,当然可以考虑使用Lock和unLock
也可以考虑使用volatile方案,不过需要更加的谨慎罢了