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


    《Java多线程设计模式》读书笔记3

    目录:
    1 Thread-Per-Message Pattern
    2 Worker Thread Pattern
    3 Future Pattern

    ===================Thread-Per-Message Pattern===============

    Thread per message,每个消息一个线程。Message 在这里可以看作是“命令”或“请求”的意思。对每个命令或请求,分配一个线程,有这个线程执行工作,这就是Thread-Per-Message Pattern。

    Thread-Per-Message Pattern的适用场合:
    1. 适合在操作顺序无所谓时使用。
    2. 在不需要返回值的时候。
    3. 可以应用在服务器的制作上,提升响应性,降低延迟时间。

    进程和线程
    1 进程和线程最大的差异在于内存能否共享。
    通常每个进程所拥有的内存空间是各自独立的。进程不能擅自读取,改写其他进程的内存空间。因为进程的内存空间是相互独立的,所以进程无需担心被其他进程破坏的危险。而线程则是共享内存的。
    2 进程和线程另一个差异,在于context-switch的频繁程度。
    进程切换需要存储和保留的信息比较多,所以切换需要花费一些时间。然而线程需要管理的context信息比进程要少得多,所以一般而言线程context-switch比进程的context-switch要快的多。

    ===================Worker Thread Pattern===============

    线程池机制 主要解决每次请求都要建立新线程的成本。事先启动用来执行工作的线程(工人线程)备用。并使用Producer-Consumer Pattern,将表示工作内容的实例传递给工人线程。这么一来,工人线程会负责执行工作,就不需要一直启动新的线程了。
    实现:

    工作区(核心)
    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; 
      } 
    }

    请求对象
    public class Request { 
      private final String name; // 委托者 
      private final int number; // 请求编号 
      private static final Random random = new Random(); 
      public Request(String name, int number) { 
        this.name = name; 
        this.number = number; 
      } 
      public void execute() { 
        System.out.println(Thread.currentThread().getName() + " executes " + this); 
        try { 
          Thread.sleep(random.nextInt(1000)); 
        } catch (InterruptedException e) { 
        } 
      } 
      public String toString() { 
        return "[ Request from " + name + " No." + number + " ]"; 
      } 
    }
    工作线程
    public class WorkerThread extends Thread { 
      private final Channel channel; 
      public WorkerThread(String name, Channel channel) { 
        super(name); 
        this.channel = channel; 
      } 
      public void run() { 
        while (true) { 
          Request request = channel.takeRequest(); 
          request.execute(); 
        } 
      } 
    }
    放入请求线程
    public class ClientThread extends Thread { 
      private final Channel channel; 
      private static final Random random = new Random(); 
      public ClientThread(String name, Channel channel) { 
        super(name); 
        this.channel = channel; 
      } 
      public void run() { 
        try { 
          for (int i = 0; true; i++) { 
            Request request = new Request(getName(), i); 
            channel.putRequest(request); 
            Thread.sleep(random.nextInt(1000)); 
          } 
        } catch (InterruptedException e) { 
        } 
      } 
    }
    测试类
    public class Main { 
      public static void main(String[] args) { 
        Channel channel = new Channel(5);  // 工作线程的數量 
        channel.startWorkers(); 
        new ClientThread("Alice", channel).start(); 
        new ClientThread("Bobby", channel).start(); 
        new ClientThread("Chris", channel).start(); 
      } 
    }

    ===================Future Pattern===============

    Future是“未来”,“期货”的意思。假设有一个执行起来需要花一些时间的方法,我们就不要等待执行结果出来了,而获取一张替的“提货单”。因为获取提货单不需要花时间,这时这个“提货单”就是Future参与者。获取Future参与者的线程,会在事后再去获取执行结果。就好像那提货单去领取蛋糕一样,如果已经有执行结果了,就可以马上拿到数据。如果执行结果还没好,则继续等待到执行结果出现为止。
    Thread-Per-Message Pattern是将花费时间的工作交给别的线程,以提高程序的响应性。不过,如果我们需要得到别的线程所处理的结果时,就行不通了。若同步执行需要花一些时间的操作,会使程序响应性降低。但是,如果异步的开始执行,却无法在第一时间得知结果。这种时候就要使用Future Pattern。首先我们建立一个与处理结果具有相同接口(API)的Future参与者。接着,在开始处理时,先把Future参与者当作返回值返回。直到其他线程处理完以后,才将真正的结果设置给Future参与者。Client参与者可以通过Future参与者得到处理的结果。使用这个Pattern,可使响应性不降低,并得到想要的处理结果。

  • 相关阅读:
    jquery ajax 跨域请求【原】
    纯js异步无刷新请求(只支持IE)【原】
    正则表达式高级用法【原】
    所有HTTP请求参数及报文查看SERVLET【原】
    AES加密【转】
    Object.prototype.toString.call() 区分对象类型
    js中的preventDefault与stopPropagation详解
    在项目中如何利用分页插件呢?
    Iframe 在项目中的使用总结
    在项目中那个少用if else 语句,精简代码,便于维护的方法(1)
  • 原文地址:https://www.cnblogs.com/gaojing/p/1755645.html
Copyright © 2020-2023  润新知