多线程设计模式

Java多线程设计模式,帮助多线程功能提升质量,下降学习成本。主要的Pattern以下:
1.Singl e Threaded Execution Pattern 多个线程共享一个实例,这样的话,多个线程都
   擅自改动实例的状态,实例会丧失安全性。这种状况能够经过Java的关键词synchronized来解决。如多我的
   经过一个gate时,只能一个个经过,那么能够以下的方式:
   public synchronized void pass(String name){
       this.name = name;
   }
   synchronized方法的性能比普通的方法低,因此下降减小使用。
   JDK中不少方法是synchronized,能够安全使用,不少为了性能是没有同步。为了提升性能能够考虑使用  Immutable Pattern
2.Immutable Pattern 多个线程共享一个实例,可是实例的状态不会改变,能够提供throughput,但必须保证
   不变形(实例的状态不会改变)。须要使用private,final等来支持。
3.Guarded Suspension Pattern 多个线程共享一个实例,这样的话,多个线程都
   擅自改动实例的状态,实例会丧失安全性。当实例的状态不恰当时,就要求线程等待到合适的状态,以“警惕条     件”来表示实例的“适当的状态”。若是警惕条件一直不成立,线程会永远等待下去,会使程序丧失生命性。Java     中用while循环来测试警惕条件,使用wait方法让线程等待,并使用notify/notifyAll通知警惕条件的改变。
检     验、修改警惕条件是,会使用Single Threaded Execution Pattern。Pattern的例子以下:
   public class RequestQueue{

           private final LinkedList queue = new LinkedList();
           public synchronized Request getRequest(){
       while(queue.size() <= 0){     //警惕条件
                try{      
              wait();
                  }catch(InterruptedException e){}
       }
       return (Request)queue.removeFirst();
           }
           public synchronized void putRequest(Request request){
              queue.addLast(request);
              notifyAll();

           }

   }


   以上使用Queue的客户端和服务器代码里面很是干净,没有多线程的东西,代码复用性很好。
   当警惕条件不成立时想要立刻退出,就使用Balking Pattern
4.Balking Pattern 一直等待安全的时机,会使程序的响应性下降。Java语言中,检验警惕条件时要使用if语句
   ,当要balk时,可以使用return退出方法,或者throw抛出异常。
   public class Data {
       private String filename;       //修改是的名字
       private String content;         // 资料的内容
       private boolean changed;       //修改后的内容还没存储的话,值为true

       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) {                                                                                    
                       System.out.println(Thread.currentThread().getName() + " balks");
                       return; //没有就退出                                                                                        
               }                                                                                                            
               doSave();                                                                                        
               changed = false;                                                                                  
       }                                                                                                                    

       // 实际资料储存到挡案里用的方法
       private void doSave() throws IOException {
               System.out.println(Thread.currentThread().getName() + " calls doSave, content = " + content);
               Writer writer = new FileWriter(filename);
               writer.write(content);
               writer.close();
       }
}

5.Producer-Consumer Pattern 当Producer参与者与Consumer参与者处理的速度不一样时,速度慢的会扯速度快的
   后腿,而下降程序的throughput。解决的办法就是在二者之间,加上中继用的Channel参与者。并让Channel
   参与者存放多条数据,这样就能够缓冲Producer和Consumer之间处理速度的差别。这个模式使用了Guarded
   Suspension Pattern。

   public class Table {
       private final String[] buffer;
       private int tail;   /下一个放put的地方
       private int head;   //下一个放的take地方
       private int count; // buffer内的蛋糕数
       public Table(int count) {
               this.buffer = new String[count];
               this.head = 0;
               this.tail = 0;
               this.count = 0;
       }
       // 放置蛋糕
       public synchronized void put(String cake) throws InterruptedException {
               System.out.println(Thread.currentThread().getName() + " puts " + cake);
               while (count >= buffer.length) {
                       wait();
               }
               buffer[tail] = cake;
               tail = (tail + 1) % buffer.length;
               count++;
               notifyAll();
       }
       // 取得蛋糕
       public synchronized String take() throws InterruptedException {
               while (count <= 0) {
                       wait();
               }
               String cake = buffer[head];
               head = (head + 1) % buffer.length;
               count--;
               notifyAll();
               System.out.println(Thread.currentThread().getName() + " takes " + cake);
               return cake;
       }
   }

6.Read-Write Lock Pattern 多个线程共享一个实例,如进程之间不进行共享胡扯,会丧失安全性。
   但使用Single Threaded Execution Pattern会使程序throughput下降。解决的方法就是将控制reader参与者的       锁定与控制writer参与者的锁定分开,加入ReadWriteLock参与者,以提供两种不一样的锁定。
 
  public final class ReadWriteLock {
       private int readingReaders = 0; // (A)...实际正在读取的执行绪数量
       private int waitingWriters = 0; // (B)...正在等待写入的执行绪数量
       private int writingWriters = 0; // (C)...实际正在写入的执行绪数量
       private boolean preferWriter = true; // 写入优先的话,值为true

       public synchronized void readLock() throws InterruptedException {
               while (writingWriters > 0 || (preferWriter && waitingWriters > 0)) {
                       wait();
               }
               readingReaders++;                                             //   (A)实际正在读取的线程数量加1
       }

       public synchronized void readUnlock() {
               readingReaders--;                                             //   (A)实际正在读取的线程数量减1
               preferWriter = true;
               notifyAll();
       }

       public synchronized void writeLock() throws InterruptedException {
               waitingWriters++;                                             // (B)正在等待写入的线程数量加1
               try {
                       while (readingReaders > 0 || writingWriters > 0) {
                               wait();
                       }
               } finally {1
                   waitingWriters--;                                     // (B)正在等待写入的线程数量减1
               }
               writingWriters++;                                             //   (C)实际正在写入的线程数量加1
       }

       public synchronized void writeUnlock() {
               writingWriters--;                                             // (C)实际正在写入的线程数量减
               preferWriter = false;
               notifyAll();
       }
   }
 
   public class Data {
       private final char[] buffer;
       private final ReadWriteLock lock = new ReadWriteLock();
       public Data(int size) {
               this.buffer = new char[size];
               for (int i = 0; i < buffer.length; i++) {
                       buffer[i] = '*';
               }
       }
       public char[] read() throws InterruptedException {
               lock.readLock();
               try {
                       return doRead();
               } finally {
                       lock.readUnlock();
               }
       }
       public void write(char c) throws InterruptedException {
               lock.writeLock();
               try {
                       doWrite(c);
               } finally {
                       lock.writeUnlock();
               }
       }
       private char[] doRead() {
               char[] newbuf = new char[buffer.length];
               for (int i = 0; i < buffer.length; i++) {
                       newbuf[i] = buffer[i];
               }
               slowly();
               return newbuf;
       }
       private void doWrite(char c) {
               for (int i = 0; i < buffer.length; i++) {
                       buffer[i] = c;
                       slowly();
               }
       }
       private void slowly() {
               try {
                       Thread.sleep(50);
               } catch (InterruptedException e) {
               }
       }
   }

7.Thread-Per-Message Pattern   在方法的属性处理完成以前,控制权不会从Host参与者退出。若是方法的处理
   属性很话费时间,程序的响应性能会下降。解决的方式就在Host的参与者里,启动新的线程,而且将该方法应       该进行的工做交给这个心的线程,这样Client参与者的线程能够继续执行下一个操做,这样作,不用更改       Client参与者的程序代码,并能提升程序的响应性。想节省启动线程所花费的时间,可使用Worker Thread       Pattern。
   public class Host {
       private final Helper helper = new Helper();
       public void request(final int count, final char c) {
               System.out.println("       request(" + count + ", " + c + ") BEGIN");
               new Thread() {
                       public void run() {
                               helper.handle(count, c);
                       }
               }.start();
               System.out.println("       request(" + count + ", " + c + ") END");
       }
   }

8.Worker Thread Pattern 若是方法的处理属性很花时间,程序的响应性会下降。为了提供响应性,而启动新
   的线程来处理方法时,启动线程所花的时间又会下降throughput。另外当送出的请求太多时,会启动
   过多的线程,这会使承载量变差。
   public class Channel {
       private static final int MAX_REQUEST = 100;
       private final Request[] requestQueue;
       private int tail;   // 下一个putRequest的地方
       private int head;   // 下一个takeRequest的地方
       private int count; // Request的数量

       private final WorkerThread[] threadPool;

       public Channel(int threads) {
               this.requestQueue = new Request[MAX_REQUEST];
               this.head = 0;
               this.tail = 0;
               this.count = 0;

               threadPool = new WorkerThread[threads];
               for (int i = 0; i < threadPool.length; i++) {
                       threadPool[i] = new WorkerThread("Worker-" + i, this);
               }
       }
       public void startWorkers() {
               for (int i = 0; i < threadPool.length; i++) {
                       threadPool[i].start();
               }
       }
       public synchronized void putRequest(Request request) {
               while (count >= requestQueue.length) {
                       try {
                               wait();
                       } catch (InterruptedException e) {
                       }
               }
               requestQueue[tail] = request;
               tail = (tail + 1) % requestQueue.length;
               count++;
               notifyAll();
       }
       public synchronized Request takeRequest() {
               while (count <= 0) {
                       try {
                               wait();
                       } catch (InterruptedException e) {
                       }
               }
               Request request = requestQueue[head];
               head = (head + 1) % requestQueue.length;
               count--;
               notifyAll();
               return request;
       }
   }

9.Future Pattern 当Client会将工做委托给其余线程,而Client参与者但愿获得处理的结果。将工做委托给
   别人时,若是又等待执行结果,会使响应性下降。
   public class FutureData implements Data {
       private RealData realdata = null;
       private boolean ready = false;
       public synchronized void setRealData(RealData realdata) {
               if (ready) {                                              
                       return;         // balk
               }
               this.realdata = realdata;
               this.ready = true;
               notifyAll();
       }
       public synchronized String getContent() {
               while (!ready) {
                       try {
                               wait();
                       } catch (InterruptedException e) {
                       }
               }
               return realdata.getContent();
       }
   }

附多线程程序的评价标准
一、安全性——不损坏对象 对象损坏是指对象的状态不符合设计师的原意,一般是获取对象的状态值并不是预期值。
二、生存性——进行必要的处理 也许不是如今,可是必定会进行必要的处理,若是程序安全了,可是有些必要的处理得不到操做,那么这个多线程程序也是不合格的。
三、复用性——可再利用类 写多线程程序,若是可以将多线程的共享和互斥结构隐藏在类里面,这就是一个高度可复印的程序。
四、性能——能快速大量处理 主要表如今吞吐量(Throughput)即必定时间内能完成的处理量,能完成的处理量越多,表示数据吞吐量越大;容量(Capacity)指可同时处理 的数量;响应性(Responsiveness)指从发出请求到收到响应的时间,时间越短,响应性越高。
五、伸缩性(Scalability)等

前两个是必要条件,后面几个是程序质量的描述
相关文章
相关标签/搜索