zoukankan      html  css  js  c++  java
  • 《图解Java多线程设计模式》之五:Balking 模式

    一,什么是Balking模式

    如果现在不合适执行这个操作,或者没必要执行这个操作,就停止处理,直接返回。
    在Balking模式中,如果守护条件不成立,就立即中断处理。

    二,例子:

    定期将当前数据内容写入文件中,比如文本工具的自动保存功能,定期的将数据保存到文件中。
    当数据内容被写入时,会完全覆盖上次写入的内容,只有最新的内容才会被保存
    当写入的内容和上次的内容完全相同时,再向文件写入就多余了,所以就不再执行写入操作。
    所以这个程序就是以 数据内容不同 作为守护条件,如果数据内容相同,就不执行写入操作,直接返回(balk)

    代码:

    Data类:可以修改并保存的数据的类

    ChangerThread类:模仿用户,进行文本的修改并随时保存

    SaverThread类:执行自动保存的线程

    public class Data {
    
        private final String filename;
        private String content;
        private boolean changed;
    
        public Data(String filename, String content) {
            this.filename = filename;
            this.content = content;
            this.changed = true;
        }
        //修改了数据内容
        public synchronized void change(String newContent){
            content = newContent;
            changed = true;
        }
        //若数据修改过,则保存到文件中
        public synchronized void save() throws IOException{
            if (!changed){
                //如果没有修改,就不保存了
                return;
            }
            doSave();
            changed = false;
        }
        //将数据内容保存到文件中
        public void doSave() throws IOException{
            System.out.println(Thread.currentThread().getName()+" calls doSave, content ="+content);
            Writer writer = new FileWriter(filename);
            writer.write(content);
            writer.close();
        }
    }
    public class ChangerThread extends Thread{
    
        private final Data data;
        private final Random random = new Random();
    
        public ChangerThread(String name,Data data) {
            super(name);
            this.data = data;
        }
    
        @Override
        public void run() {
            try {
                for (int i = 0; true; i++) {
                    data.change("NO."+i);//修改数据
                    Thread.sleep(random.nextInt(1000));//执行其他操作
                    data.save();//显示的保存,用户自己点击保存
                }
            }catch (IOException e){
                e.printStackTrace();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
    
        }
    }
    public class SaverThread extends Thread{
        private final Data data;
    
        public SaverThread(String name,Data data) {
            super(name);
            this.data = data;
        }
    
        @Override
        public void run() {
            try {
                while (true){
                    data.save();//要求保存数据
                    Thread.sleep(1000);//休眠约一秒
                }
            }catch (IOException e){
                e.printStackTrace();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    public class Test {
        public static void main(String[] args) {
            Data data = new Data("data.txt","(empty)");
            new ChangerThread("ChangeThread",data).start();
            new SaverThread("SaverThread",data).start();
    
    
        }
    }

    三,GurardedObject:被防护的对象

    GuardedObject角色是一个拥有被防护的方法的类。当线程执行guardedMethod时,若守护条件成立,则执行实际的处理。
    当守护条件不成立时,不执行实际的处理,直接返回。守护条件是否成立,会随着GuardedObject角色的状态变化而变化
    Data类就是被防护的对象
    save方法对应guardedMethod
    change方法对应stateChangingMethod

    四,何时使用Balking模式

    1.并不需要执行时:
    比如上面的程序中,文件已经手动保存了,并且文本内容也没有改变,就不需要再执行自动保存了。这样可以提高程序性能
    2.不需要等待守护条件成立时
    当守护条件不成立时,就立即返回并进入下一个操作,就可以使用这种模式。这能够提高程序的响应性
    3.守护条件仅在一次成立时
    相当于没有stateChangingMethod方法的情况
    例子:

    public class Something{
        private boolean initialized = false;
        public synchronized void init(){
            if(initialized){
                return;        
            }
            doInit();
            initialized = true;
        
        }
    
        public void doInit(){
            //实际处理初始化
        }
    }

    //如果没有初始化,就做一次初始化动作。如果已经初始化就什么也不做。直接返回

    五,balk结果的表示方式

    1.忽略balk
    不通知调用端发生了balk,比如实例程序中直接return
    2.通过返回值来表示balk
    比如返回值为true,表明为发生balk。如果返回值为false,说明发生了balk,处理并未被执行
    3.通过异常来表示balk的发生
    当balk发生时,程序并不是从方法中retrun,而是直接抛出异常

    六,超时

    Balking模式中,当守护条件不成立时,线程会直接balk并返回
    而Guarded Suspension模式中,当守护条件不成立时,线程会一直等待到成立为止。
    这两种模式都比较极端。还有一种处理方方法,在守护条件成立之前等待一段时间,如果到时条件还未成立,则直接balk。这种处理称为 guarded timed或timeout

    1.wait何时终止?
    当执行: obj.wait();时,线程进入obj的等待队列,停止运行,并释放持有的obj锁。当下面情况发生时,线程就会退出等待线程:
    notify方法执行
    notifyAll方法执行
    interrupt方法执行
    超时发生时

    2.guarded timed的实现
    从上面的方法得知,我们无法区分wait方法是被notify/notifyAll了,还是超时了,所以自己要实现guarded timed。判断wait是否超时
    代码:

    public class Host {
    
        private final long timeout;//超时时间
        private boolean ready = false;//方法正常执行时为true
    
        public Host(long timeout){
            this.timeout = timeout;
        }
    
        //修改状态
        public synchronized void setExecutable(boolean on){
            ready =on;
            notifyAll();
        }
        //检查状态后在执行
        public synchronized void execute()throws InterruptedException,TimeoutException{
            long start = System.currentTimeMillis();//开始时间
            while (!ready){
                long now = System.currentTimeMillis();//当前时间
                long rest = timeout - (now -start);
           //在这里只要 <=0,我们就认为超时。(因为wait方法的参数为0时,就表示没有超时时间(超时时间无限长),当传入负数时,会抛出IllegalArgumentException异常。)
    if (rest <= 0){ throw new TimeoutException("now - start= "+(now-start)+", timeout = "+timeout); } wait(rest); }      doExecute(); } //实际的处理 private void doExecute(){ System.out.println(Thread.currentThread().getName()+" calls doExecute"); } }
    /*
    如果Host的方法执行时,不调用setExecutable(true),程序就会出现超时
    */
    public
    class Test { public static void main(String[] args) { Host host = new Host(10000); try { System.out.println("execute Begin"); host.execute(); }catch (TimeoutException e){ e.printStackTrace(); }catch (InterruptedException e){ e.printStackTrace(); } } }

    执行结果:

    execute Begin
    java.util.concurrent.TimeoutException: now - start= 10001, timeout = 10000  //误差1毫秒
        at com.amazing.jdk.myThread.package12.Host.execute(Host.java:29)
        at com.amazing.jdk.myThread.package12.Test.main(Test.java:14)

  • 相关阅读:
    MySQL优化---主从复制
    MySQL性能优化---优化方案
    MySQL性能优化---索引
    MySQL性能优化---定位慢查询
    Linux开机启动过程详解
    naginx
    Git搭建
    脚本中特殊字符
    Shell脚本
    简单Shell脚本(实例)
  • 原文地址:https://www.cnblogs.com/inspred/p/9385897.html
Copyright © 2011-2022 走看看