zoukankan      html  css  js  c++  java
  • 多线程程序设计学习(5)balking模式和timed模式

    Balking【返回模式】timed【超时模式】
    一:balking pattern的参与者
    --->GuardedObject(被警戒的对象)

    --->该模式的角色:模拟修改警戒对象的线程,当警戒条件达到执行具体操作的线程,参与者(被警戒的参与者)
           

    二:balking pattern模式什么时候使用
    --->不需要刻意去执行什么操作的时候(比如说自动保存)
    --->不想等待警戒条件成立时。(不让线程休息)
    --->警戒条件只有第一次成立时候。
       

    三:balking pattern思考
    --->balking pattern (返回模式)和Guarded suspension pattern(等待唤醒模式)的中间
            3.1Guarded suspension当警戒条件不成立时,会等待,直到成立,并被唤醒。
            3.2balking 当警戒条件不成立,退出。
            3.3两种极端的处理方式之间还有一种折衷的做法。在条件成立为止之前,等待一段时间,看看条件是否成立,如果不成立,则balk。这种方式称之为guarded timed 或简单称之为timeOut
    ---->线程类中的各个唤醒方法
            3.1:当notify方法执行时==>如果wait set里有多条线程,只有一条被唤醒
            3.2:当notifyAll方法执行时==>wait set里有多少条线程都被唤醒。
            3.3:interrupt方法执行时==>wait set里的线程会(与调用notify,notifyAll一样)重新尝试获取锁定。
                                                           ==> notify,notifyAll是对实例调用的,而interrupt是对线程调用的。关于中断,后续会提到。
            3.4:发生timeout时,由于wait(超时时间),和被notify或notifyAll唤醒重新尝试获取锁定,分不清楚,所以timeout需要程序员自己写。

    ---->sleep和wait的区别有:
      1,这两个方法来自不同的类分别是Thread和Object
      2,最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
      3,wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在
        任何地方使用
       synchronized(x){
          x.notify()
         //或者wait()
       }
       4,sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
       5.wait被唤醒后,重新获取锁,从阻塞的代码处继续往下执行。和sleep一样。

    Balking【返回模式】案例:模拟自动保存文件,当文件没有更改时,每隔一秒的自动保存数据,真正保存操作不执行。如果有修改,则执行真正保存操作。

    数据类

     1 package com.yeepay.sxf.thread4;
     2 
     3 import java.io.File;
     4 import java.io.FileOutputStream;
     5 import java.io.IOException;
     6 
     7 /**
     8  * 数据类。
     9  * @author sxf
    10  *
    11  */
    12 public class Data {
    13     //文件名
    14     private String fileName;
    15     //文件内容
    16     private String content;
    17     //表示是否被修改过
    18     private boolean flag;
    19     //构造器
    20     public Data(String fileName, String content) {
    21         super();
    22         this.fileName = fileName;
    23         this.content = content;
    24         this.flag=true;
    25         File file =new File(fileName);
    26         try {
    27             file.createNewFile();
    28             FileOutputStream iFileOutputStream=new FileOutputStream(file);
    29             iFileOutputStream.write(content.getBytes());
    30         } catch (IOException e) {
    31             // TODO Auto-generated catch block
    32             e.printStackTrace();
    33         }
    34     }
    35     //修改内容
    36     public synchronized void channgeContent(String newContent){
    37         this.content=newContent ;
    38         flag=true;
    39     }
    40     
    41     //把新的数据写入文件
    42     private void save() throws IOException{
    43         System.out.println("Data.save()"+Thread.currentThread().getName()+"执行写入操作,写入的内容为:"+content);
    44         FileOutputStream fileWriter=new FileOutputStream(new File(fileName));
    45         fileWriter.write(content.getBytes());
    46     }
    47     
    48     //保存内容
    49     public synchronized void saveNewContent(){
    50         if(!flag){
    51             System.out.println("Data.saveNewContent(试图新保存,但没有更改)");
    52             return;
    53         }
    54         try {
    55             save();
    56             System.out.println("Data.saveNewContent(新内容保存成功)");
    57             flag=false;
    58         } catch (IOException e) {
    59             e.printStackTrace();
    60         }
    61     }
    62 }
    View Code

    模拟修改数据的线程

     1 package com.yeepay.sxf.thread4;
     2 /**
     3  * 模拟自动修改线程
     4  * @author sxf
     5  *
     6  */
     7 public class ChangeThread implements Runnable{
     8     private Data data;
     9 
    10     public ChangeThread(Data data) {
    11         super();
    12         this.data = data;
    13     }
    14 
    15     @Override
    16     public void run() {
    17         for(int i=0;i<20;i++){
    18             //修改内容
    19             System.out.println("ChangeThread.run()"+Thread.currentThread().getName()+"第"+i+"次修改");
    20             data.channgeContent("新内容"+i);
    21             //线程休息10秒
    22             try {
    23                 Thread.sleep(10000L);
    24             } catch (InterruptedException e) {
    25                 // TODO Auto-generated catch block
    26                 e.printStackTrace();
    27             }
    28         }
    29     }
    30 
    31     
    32 }
    View Code

    模拟自动保存的线程

     1 package com.yeepay.sxf.thread4;
     2 /**
     3  * 自动保存的线程
     4  * @author sxf
     5  *
     6  */
     7 public class ZiDongSaveThread implements Runnable{
     8     private Data data;
     9 
    10     
    11     public ZiDongSaveThread(Data data){
    12         this.data=data;
    13     }
    14     @Override
    15     public void run() {
    16         while(true){
    17             //保存数据
    18             data.saveNewContent();
    19             //线程休息1秒,意味着每隔一妙钟自动保存一次文件
    20             try {
    21                 Thread.sleep(1000L);
    22             } catch (InterruptedException e) {
    23                 // TODO Auto-generated catch block
    24                 e.printStackTrace();
    25             }
    26         }
    27         
    28     }
    29     
    30 }
    View Code

    测试类

     1 package com.yeepay.sxf.thread4;
     2 /**
     3  * 测试类
     4  * @author sxf
     5  *
     6  */
     7 public class Test {
     8     
     9     
    10 public static void main(String[] args) {
    11     //声明内容
    12     Data data=new Data("/usr/war/hsl.txt", "老黄买了新手机");
    13     //声明自动保存线程
    14     Thread saveThread=new Thread(new ZiDongSaveThread(data));
    15     saveThread.setName("自动保存线程");
    16     //声明模拟修改线程
    17     Thread chaThread=new Thread(new ChangeThread(data));
    18     chaThread.setName("模拟修改线程");
    19     
    20     //启动线程
    21     saveThread.start();
    22     chaThread.start();
    23     
    24     
    25 }
    26 }
    View Code

     打印结果

    Data.save()自动保存线程执行写入操作,写入的内容为:老黄买了新手机
    Data.saveNewContent(新内容保存成功)
    ChangeThread.run()模拟修改线程第0次修改
    Data.save()自动保存线程执行写入操作,写入的内容为:新内容0
    Data.saveNewContent(新内容保存成功)
    Data.saveNewContent(试图新保存,但没有更改)
    Data.saveNewContent(试图新保存,但没有更改)
    Data.saveNewContent(试图新保存,但没有更改)
    Data.saveNewContent(试图新保存,但没有更改)
    Data.saveNewContent(试图新保存,但没有更改)
    Data.saveNewContent(试图新保存,但没有更改)
    Data.saveNewContent(试图新保存,但没有更改)
    Data.saveNewContent(试图新保存,但没有更改)
    Data.saveNewContent(试图新保存,但没有更改)
    ChangeThread.run()模拟修改线程第1次修改
    Data.save()自动保存线程执行写入操作,写入的内容为:新内容1
    Data.saveNewContent(新内容保存成功)
    Data.saveNewContent(试图新保存,但没有更改)
    Data.saveNewContent(试图新保存,但没有更改)
    Data.saveNewContent(试图新保存,但没有更改)
    Data.saveNewContent(试图新保存,但没有更改)

    timed【超时模式】案例:一个线程提供下载数据,另一个线程执行下载,如果有5秒钟以上,提供下载的线程没有提供数据,下载线程因超时异常,停止下载线程运行。

    超时异常类

     1 package com.yeepay.sxf.thread4;
     2 /**
     3  * 超时异常类
     4  * @author sxf
     5  *
     6  */
     7 public class TimeOutException extends InterruptedException {
     8 
     9     public TimeOutException(String msg){
    10         super(msg);
    11     }
    12 }
    View Code

    下载数据的数据类

     1 package com.yeepay.sxf.thread4;
     2 /**
     3  * 下载数据类
     4  * @author sxf
     5  *
     6  */
     7 public class FileData {
     8     //提供下载的数据
     9     private String data;
    10     //有数据可下载
    11     private boolean flag;
    12     //超时时间
    13     private long timeout;
    14     
    15     //构造器
    16     public FileData(String data, boolean flag, long timeout) {
    17         super();
    18         this.data = data;
    19         this.flag = flag;
    20         this.timeout = timeout;
    21     }
    22     
    23     
    24     //修改状态,唤醒其他所有线程
    25     public synchronized void  changeStatus(String data){
    26         this.data=data;
    27         flag=true;
    28         notify();
    29     }
    30     
    31     //下载操作。如果等timeout/1000秒钟,没有数据供下载,就报超时异常,终止下载
    32     public synchronized void execu() throws InterruptedException{
    33         //开始执行的时间
    34         long start=System.currentTimeMillis();
    35         int i=0;
    36         System.out.println("FileData.execu(开始时间1)");
    37         while (!flag) {
    38             //现在的时间
    39             long now=System.currentTimeMillis();
    40             long reset=timeout-(now-start);
    41             if(reset<=0){
    42                 throw new TimeOutException("已经等候"+timeout+"时间了还没有数据可供下载,超时");
    43             }
    44             //如果没有超时,就让下载线程进入wait set,设置超时时间。被唤醒,继续从这里开始执行。
    45             wait(reset);
    46         }
    47         //真正的下载操作
    48         download();
    49     }
    50     
    51     
    52     //真正的下载操作
    53     private void download(){
    54         System.out.println("顺利下载数据==>:"+data);
    55         //下载完之后,将下载状态改为不可下载,等待放入新数据供下载
    56         this.flag=false;
    57     }
    58     
    59     public String getData() {
    60         return data;
    61     }
    62     public void setData(String data) {
    63         this.data = data;
    64     }
    65     public boolean isFlag() {
    66         return flag;
    67     }
    68     public void setFlag(boolean flag) {
    69         this.flag = flag;
    70     }
    71     
    72     
    73     
    74     public long getTimeout() {
    75         return timeout;
    76     }
    77     public void setTimeout(long timeout) {
    78         this.timeout = timeout;
    79     }
    80 }
    View Code

    提供数据供下载的线程类

     1 package com.yeepay.sxf.thread4;
     2 /**
     3  *制造数据线程
     4  * @author sxf
     5  *
     6  */
     7 public class GiveDataThread implements Runnable {
     8     //公共数据
     9     private FileData fileData;
    10     
    11     //构造器
    12     public GiveDataThread(FileData fileData) {
    13         super();
    14         this.fileData = fileData;
    15     }
    16 
    17 
    18 
    19     @Override
    20     public void run() {
    21             //制造数据线程,造100个数据
    22             for (int i = 0; i <10; i++) {
    23                 fileData.changeStatus("制造数据"+i);
    24                 System.out.println("【制造线程制造数据】==》制造数据"+i);
    25                 try {
    26                     Thread.sleep(1000);
    27                 } catch (InterruptedException e) {
    28                     // TODO Auto-generated catch block
    29                     e.printStackTrace();
    30                 }
    31                 
    32         }
    33         
    34     }
    35 
    36     
    37 }
    View Code

    下载数据的线程类

     1 package com.yeepay.sxf.thread4;
     2 /**
     3  * 下载线程
     4  * @author sxf
     5  *
     6  */
     7 public class DownLoadThread implements Runnable {
     8     private FileData fileData;
     9     private boolean flag=true;
    10     //构造器
    11     public DownLoadThread(FileData fileData) {
    12         super();
    13         this.fileData = fileData;
    14     }
    15 
    16     @Override
    17     public void run() {
    18         //开始下载线程
    19         System.out.println("DownLoadThread.run(下载线程开始");
    20         //根据标识
    21         while(flag){
    22             //进行下载
    23             try {
    24                 fileData.execu();
    25             } catch (TimeOutException e) {
    26                 e.printStackTrace();
    27                 flag=false;
    28             }catch (InterruptedException e) {
    29                 // TODO: handle exception
    30                 System.out.println("DownLoadThread.run(非超时异常)");
    31             }
    32         }
    33         
    34         System.out.println("DownLoadThread.run(下载线程因为超时,而执行完毕)");
    35     }
    36     
    37     
    38     
    39     
    40 
    41 }
    View Code

    测试类

     1 package com.yeepay.sxf.thread4;
     2 /**
     3  * 测试超时模式
     4  * @author sxf
     5  *
     6  */
     7 public class Test2 {
     8     
     9     
    10     public static void main(String[] args) {
    11         //声明数据类
    12         FileData data=new FileData("sxf",true,5000);
    13         //声明生产数据的线程
    14         Thread giveThread=new Thread(new GiveDataThread(data));
    15         //声明下载数据的线程
    16         Thread downThread=new Thread(new DownLoadThread(data));
    17         
    18         //启动线程
    19         giveThread.start();
    20         downThread.start();
    21     }
    22 }
    View Code

    打印结果

    【制造线程制造数据】==》制造数据0
    DownLoadThread.run(下载线程开始
    FileData.execu(开始时间1)
    顺利下载数据==>:制造数据0
    FileData.execu(开始时间1)
    【制造线程制造数据】==》制造数据1
    顺利下载数据==>:制造数据1
    FileData.execu(开始时间1)
    【制造线程制造数据】==》制造数据2
    顺利下载数据==>:制造数据2
    FileData.execu(开始时间1)
    【制造线程制造数据】==》制造数据3
    顺利下载数据==>:制造数据3
    FileData.execu(开始时间1)
    【制造线程制造数据】==》制造数据4
    顺利下载数据==>:制造数据4
    FileData.execu(开始时间1)
    【制造线程制造数据】==》制造数据5
    顺利下载数据==>:制造数据5
    FileData.execu(开始时间1)
    【制造线程制造数据】==》制造数据6
    顺利下载数据==>:制造数据6
    FileData.execu(开始时间1)
    【制造线程制造数据】==》制造数据7
    顺利下载数据==>:制造数据7
    FileData.execu(开始时间1)
    【制造线程制造数据】==》制造数据8
    顺利下载数据==>:制造数据8
    FileData.execu(开始时间1)
    【制造线程制造数据】==》制造数据9
    顺利下载数据==>:制造数据9
    FileData.execu(开始时间1)
    DownLoadThread.run(下载线程因为超时,而执行完毕)
    com.yeepay.sxf.thread4.TimeOutException: 已经等候5000时间了还没有数据可供下载,超时
        at com.yeepay.sxf.thread4.FileData.execu(FileData.java:42)
        at com.yeepay.sxf.thread4.DownLoadThread.run(DownLoadThread.java:24)
        at java.lang.Thread.run(Thread.java:662)

  • 相关阅读:
    一个通用的事件监听函数全集
    单应性矩阵
    opencv姿态估计
    opencv相机标定
    Harris角点
    盒滤波Box Filter
    win10+vs2015+pcl1.8.1安装配置
    图像元素遍历
    阈值分割
    二叉树的层次遍历
  • 原文地址:https://www.cnblogs.com/shangxiaofei/p/4657516.html
Copyright © 2011-2022 走看看