• Java多线程设计模式(三)


     

    Read-Wirte Lock Pattern

            Read-Write Lock Pattern 将读取和写入分开来处理。在读取数据之前,必须获取用来读取的锁定。而要写入的时候,则必须获取用来写入的锁定。因为进行读取时,实例的状态不会改变,所 以,就算有多个线程在同时读取也没有关系。但当有线程在进行写入的时候,不可以再进行写入的操作。写入的时候,实例的状态会改变。于是,当有一个线程在写 入的时候,其他线程就不可以进行读取或写入。一般来说,进行共享互斥会使程序性能变差,但将写入的共享互斥与读取的共享互斥拆分开来,就可以提高程序的性 能
    [java] view plaincopy
     
    1. public class ReadWriteLock {  
    2.   
    3.     /** 
    4.      * 正在读取的线程数 
    5.      */  
    6.     private int     readingThreadsNumber;  
    7.   
    8.     /** 
    9.      * 正在写入的线程数(最多为1) 
    10.      */  
    11.     private int     writingThreadsNumber;  
    12.   
    13.     /** 
    14.      * 等待写入的线程数 
    15.      */  
    16.     private int     waitingWriteThreadsNumber;  
    17.   
    18.     /** 
    19.      * 是否优先写入,true:优先写入;false:优先读取 
    20.      */  
    21.     private boolean preferWriter = true;  
    22.   
    23.     public synchronized void readLock() throws InterruptedException {  
    24.         // 如果有线程正在写入或者优先写入时,有线程正在等待写入,读取线程则等待  
    25.         while (this.writingThreadsNumber > 0  
    26.                 || (this.preferWriter && this.waitingWriteThreadsNumber > 0)) {  
    27.             wait();  
    28.         }  
    29.   
    30.         this.readingThreadsNumber++;  
    31.     }  
    32.   
    33.     public synchronized void readUnlock() throws InterruptedException {  
    34.         this.readingThreadsNumber--;  
    35.         this.preferWriter = true;  
    36.         notifyAll();  
    37.     }  
    38.   
    39.     public synchronized void writeLock() throws InterruptedException {  
    40.         this.waitingWriteThreadsNumber++;  
    41.         // 如果有线程正在写入或者正在读取,当前写入线程等待  
    42.         try {  
    43.             while (this.writingThreadsNumber > 0 || this.readingThreadsNumber > 0) {  
    44.                 wait();  
    45.             }  
    46.         } finally {  
    47.             this.waitingWriteThreadsNumber--;  
    48.         }  
    49.   
    50.         this.writingThreadsNumber++;  
    51.     }  
    52.   
    53.     public synchronized void writeUnlock() throws InterruptedException {  
    54.         this.writingThreadsNumber--;  
    55.         this.preferWriter = false;  
    56.         notifyAll();  
    57.     }  
    58.   
    59. }  

    [java] view plaincopy
     
    1. public class Data {  
    2.   
    3.     private char[]        buffer;  
    4.   
    5.     private ReadWriteLock readWriteLock = new ReadWriteLock();  
    6.   
    7.     public Data(int size) {  
    8.         this.buffer = new char[size];  
    9.         for (int i = 0; i < size; i++) {  
    10.             this.buffer[i] = '*';  
    11.         }  
    12.     }  
    13.   
    14.     public char[] read() throws InterruptedException {  
    15.         try {  
    16.             readWriteLock.readLock();  
    17.             return doRead();  
    18.         } finally {  
    19.             readWriteLock.readUnlock();  
    20.         }  
    21.     }  
    22.   
    23.     public void write(char c) throws InterruptedException {  
    24.         try {  
    25.             readWriteLock.writeLock();  
    26.             doWrite(c);  
    27.         } finally {  
    28.             readWriteLock.writeUnlock();  
    29.         }  
    30.     }  
    31.   
    32.     private char[] doRead() {  
    33.         char[] newChars = new char[buffer.length];  
    34.         System.arraycopy(this.buffer, 0, newChars, 0this.buffer.length);  
    35.         slowly();  
    36.         return newChars;  
    37.     }  
    38.   
    39.     private void doWrite(char c) {  
    40.         for (int i = 0; i < this.buffer.length; i++) {  
    41.             this.buffer[i] = c;  
    42.             slowly();  
    43.         }  
    44.     }  
    45.   
    46.     private void slowly() {  
    47.         try {  
    48.             Thread.sleep(100);  
    49.         } catch (InterruptedException e) {  
    50.         }  
    51.     }  
    52. }  


    [java] view plaincopy
     
    1. import java.util.Random;  
    2.   
    3. public class ReaderThread extends Thread {  
    4.   
    5.     private static final Random random = new Random();  
    6.   
    7.     private final Data          data;  
    8.   
    9.     public ReaderThread(Data data) {  
    10.         this.data = data;  
    11.     }  
    12.   
    13.     @Override  
    14.     public void run() {  
    15.         while (true) {  
    16.             try {  
    17.                 char[] c = data.read();  
    18.                 System.out.println(Thread.currentThread().getName() + "reads " + String.valueOf(c));  
    19.                 Thread.sleep(random.nextInt(1000));  
    20.             } catch (InterruptedException e) {  
    21.             }  
    22.         }  
    23.     }  
    24.   
    25. }  


    [java] view plaincopy
     
    1. import java.util.Random;  
    2.   
    3. public class WriterThread extends Thread {  
    4.   
    5.     private static final Random random = new Random();  
    6.   
    7.     private final Data          data;  
    8.   
    9.     private final String        filler;  
    10.   
    11.     private int                 index  = 0;  
    12.   
    13.     public WriterThread(Data data, String filler) {  
    14.         this.data = data;  
    15.         this.filler = filler;  
    16.     }  
    17.   
    18.     @Override  
    19.     public void run() {  
    20.         while (true) {  
    21.             char c = nextChar();  
    22.             try {  
    23.                 data.write(c);  
    24.                 Thread.sleep(random.nextInt(1000));  
    25.             } catch (InterruptedException e) {  
    26.             }  
    27.         }  
    28.     }  
    29.   
    30.     private char nextChar() {  
    31.         char c = filler.charAt(index);  
    32.         index++;  
    33.         if (index > filler.length()) {  
    34.             index = 0;  
    35.         }  
    36.   
    37.         return c;  
    38.     }  
    39. }  


    [java] view plaincopy
     
    1. public class MainThread {  
    2.   
    3.     public static void main(String[] args) {  
    4.         int bufferSize = 10;  
    5.         Data data = new Data(bufferSize);  
    6.   
    7.         new ReaderThread(data).start();  
    8.         new ReaderThread(data).start();  
    9.         new ReaderThread(data).start();  
    10.         new ReaderThread(data).start();  
    11.         new ReaderThread(data).start();  
    12.         new ReaderThread(data).start();  
    13.         new ReaderThread(data).start();  
    14.   
    15.         String filler1 = "abcdefghjklmnopqrstuvwxyz";  
    16.         String filler2 = "ABCDEFGHJKLMNOPQRSTUVWXYZ";  
    17.         new WriterThread(data, filler1).start();  
    18.         new WriterThread(data, filler2).start();  
    19.   
    20.     }  
    21.   
    22. }  
            单纯使用Single Thread Execution Pattern时,就连read的操作一次也只有一条线程可以执行。如果read操作比较频繁或比较耗时,那使用Read-Write Lock Pattern会比Single Thread Execution Pattern好很多。但因为Read-Write Lock Pattern的程序比Single Thread Execution Pattern实现复杂,如果read操作很简单,那么使用Single Thread Execution Pattern可能性能反而较高。 Read-Write Lock Pattern的优点在于Reader参与者之间不会起冲突。不过,当wirte操作比较频繁时,Writer参与者会经常阻挡Reader参与者的进 行,这样就无法展现Read-Write Lock Pattern的优点。

            在ReadWriteLock类中,提供了“读访问锁定”和“写访问锁定”两种逻辑上的锁定,但在“物理”上只用到了一个锁定,即ReadWriteLock实例的锁定。




    Thread-Per-Message Pattern

    thread per message 就是每一个消息一个线程。对每一个命令或请求,分配一个线程,由这个线程执行工作,这就是Thread-Per-Message Pattern。

    [java] view plaincopy
     
    1. public class Helper {  
    2.   
    3.     public void handle(int count, char c) {  
    4.         System.out.println("handle(" + count + ", " + c + ") BEGIN");  
    5.         for (int i = 0; i < count; i++) {  
    6.             System.out.print(c);  
    7.             slowly();  
    8.         }  
    9.         System.out.println("");  
    10.         System.out.println("handle( " + count + ", " + c + ") END");  
    11.     }  
    12.   
    13.     private void slowly() {  
    14.         try {  
    15.             Thread.sleep(50);  
    16.         } catch (InterruptedException e) {  
    17.         }  
    18.     }  
    19. }  
    20.   
    21.   
    22.   
    23. public class Host {  
    24.   
    25.     private final Helper helper = new Helper();  
    26.   
    27.     public void request(final int count, final char c) {  
    28.         System.out.println("reqeust (" + count + ", " + c + ") BEGIN");  
    29.         new Thread() {  
    30.             @Override  
    31.             public void run() {  
    32.                 helper.handle(count, c);  
    33.             }  
    34.         }.start();  
    35.         System.out.println("reqeust (" + count + ", " + c + ") END");  
    36.     }  
    37.   
    38.     public static void main(String[] args) {  
    39.         System.out.println("main Begin");  
    40.   
    41.         Host host = new Host();  
    42.         host.request(10'a');  
    43.         host.request(20'b');  
    44.         host.request(30'c');  
    45.   
    46.         System.out.println("main End");  
    47.     }  
    48.   
    49. }  

    该模式适合在操作顺序无所谓的请求时。如果操作顺序有意义时,不适合适用Thread-Per-Message Pattern。另外不需要返回值的时候也是适合使用该模式的。


    在该模式里,由于每个请求都需要启动一个线程,那么启动线程以及线程上下文的切换就成为了系统的瓶颈点,为了降低线程的启动所需的时间,可以使用Worker Thread Pattern



    Worker Thread Pattern

         Woker Thread Pattern可以看作是Thread-Per-Message Pattern的改进,该模式定义了一个线程池,线程池里面的线程被称作Worker Thread。由于在系统启动时,这些Worker Thread已经准备好了,当请求来时,不需要在进行重现启动,并且系统中也维持了一定数量的Worker Thread,而不是不断的启动新线程,在性能上要优于Thread-Per-Message Pattern。
    [java] view plaincopy
     
    1. import java.util.Random;  
    2.   
    3. public class Request {  
    4.   
    5.     private final String        name;  
    6.   
    7.     private final int           number;  
    8.   
    9.     private final static Random random = new Random();  
    10.   
    11.     public Request(String name, int number) {  
    12.         this.name = name;  
    13.         this.number = number;  
    14.     }  
    15.   
    16.     public void request() {  
    17.         System.out.println(Thread.currentThread().getName() + " " + toString());  
    18.         try {  
    19.             Thread.sleep(random.nextInt(1000));  
    20.         } catch (InterruptedException e) {  
    21.         }  
    22.     }  
    23.   
    24.     @Override  
    25.     public String toString() {  
    26.         return "[ Reqeust name = " + name + ", number = " + number + " ]";  
    27.     }  
    28. }  
    [java] view plaincopy
     
    1. import java.util.LinkedList;  
    2.   
    3. public class Channel {  
    4.   
    5.     private final LinkedList<Request> buffers    = new LinkedList<Request>();  
    6.   
    7.     private static final int          bufferSize = 100;  
    8.   
    9.     private WorkerThread[]            threadPool;  
    10.   
    11.     public Channel(int threads) {  
    12.         this.threadPool = new WorkerThread[threads];  
    13.   
    14.         for (int i = 0; i < threads; i++) {  
    15.             threadPool[i] = new WorkerThread("WorkerThread-" + (i + 1), this);  
    16.         }  
    17.     }  
    18.   
    19.     public void startWorkers() {  
    20.         for (int i = 0; i < this.threadPool.length; i++) {  
    21.             threadPool[i].start();  
    22.         }  
    23.     }  
    24.   
    25.     public synchronized void put(Request request) throws InterruptedException {  
    26.         while (this.buffers.size() >= bufferSize) {  
    27.             wait();  
    28.         }  
    29.         this.buffers.addLast(request);  
    30.         notifyAll();  
    31.     }  
    32.   
    33.     public synchronized Request take() throws InterruptedException {  
    34.         while (this.buffers.size() == 0) {  
    35.             wait();  
    36.         }  
    37.         Request request = this.buffers.removeFirst();  
    38.         notifyAll();  
    39.         return request;  
    40.     }  
    41. }  
    [java] view plaincopy
     
    1. public class WorkerThread extends Thread {  
    2.   
    3.     private Channel channel;  
    4.   
    5.     public WorkerThread(String name, Channel channel) {  
    6.         super(name);  
    7.         this.channel = channel;  
    8.     }  
    9.   
    10.     @Override  
    11.     public void run() {  
    12.         while (true) {  
    13.             try {  
    14.                 Request request = this.channel.take();  
    15.                 request.request();  
    16.             } catch (InterruptedException e) {  
    17.             }  
    18.         }  
    19.     }  
    20. }  
    [java] view plaincopy
     
    1. package workerthread;  
    2.   
    3. import java.util.Random;  
    4.   
    5. public class ClientThread extends Thread {  
    6.   
    7.     private final Channel       channel;  
    8.   
    9.     private final static Random random = new Random();  
    10.   
    11.     public ClientThread(String name, Channel channel) {  
    12.         super(name);  
    13.         this.channel = channel;  
    14.     }  
    15.   
    16.     @Override  
    17.     public void run() {  
    18.         int i = 0;  
    19.         while (true) {  
    20.             Request request = new Request(getName(), ++i);  
    21.             try {  
    22.                 this.channel.put(request);  
    23.                 Thread.sleep(random.nextInt(1000));  
    24.             } catch (InterruptedException e) {  
    25.             }  
    26.         }  
    27.     }  
    28. }  
    [java] view plaincopy
     
    1. public class Main {  
    2.   
    3.     public static void main(String[] args) {  
    4.   
    5.         int threads = 5;  
    6.         Channel channel = new Channel(threads);  
    7.   
    8.         new ClientThread("Alice", channel).start();  
    9.         new ClientThread("Bobby", channel).start();  
    10.         new ClientThread("Chris", channel).start();  
    11.   
    12.         channel.startWorkers();  
    13.     }  
    14. }  

           Worker Thread Pattern 还将方法调用和方法执行进行了分离,所以我们在该模式里面看到了设计模式里面的Command Pattern的影子,因为它们的主题都是将方法调用和方法执行进行分离。方法调用和方法执行的分离可以提高响应性,能够控制实行的顺序,我们可以对 Reqeust设立优先性,控制Channel传递Request给Worker的顺序。同时我们可以取消方法的执行,或者重复方法的执行。
          Request对象可以进行多态。由于Worker Thread并不知道Request类的具体内容,只是知道执行Request类的execute方法而已,所以我们可以建立Request类的子类,并 将其实例传给Channel,Worker Thread也能正确调用这个实例的execute方法。
    转载 blog.csdn.net/shenzhen_liubin/article/details/9825625
  • 相关阅读:
    【ML-9-1】支持向量机--软硬间隔与支持向量机
    【ML-8】感知机算法-传统和对偶形式
    【ML-7】聚类算法--K-means和k-mediods/密度聚类/层次聚类
    【ML-7】聚类算法-实例代码
    【ML-6-2】集成学习-boosting(Adaboost和GBDT )
    【ML-6-1】集成学习-bagging(随机森林)
    【ML-5】决策树算法
    【ML-4】逻辑回归--用于分类
    【ML-3.1】梯度下降于牛顿法实例
    树状数组
  • 原文地址:https://www.cnblogs.com/chenying99/p/3322037.html
Copyright © 2020-2023  润新知