多线程程序设计学习(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)

原文地址:https://www.cnblogs.com/shangxiaofei/p/4657516.html