zoukankan      html  css  js  c++  java
  • 多线程之Future模式

    详细参见葛一名老师的《Java程序性能优化》

    Futrue模式:对于多线程,如果线程A要等待线程B的结果,那么线程A没必要等待B,直到B有结果,可以先拿到一个未来的Future,等B有结果是再取真实的结果。

     在多线程中经常举的一个例子就是:网络图片的下载,刚开始是通过模糊的图片来代替最后的图片,等下载图片的线程下载完图片后在替换。而在这个过程中可以做一些其他的事情。

      首先客户端向服务器请求RealSubject,但是这个资源的创建是非常耗时的,怎么办呢?这种情况下,首先返回Client一个FutureSubject,以满足客户端的需求,于此同时呢,Future会通过另外一个Thread 去构造一个真正的资源,资源准备完毕之后,在给future一个通知。如果客户端急于获取这个真正的资源,那么就会阻塞客户端的其他所有线程,等待资源准备完毕。

      公共数据接口,FutureData和RealData都要实现。

    1 public interface Data {  
    2     public abstract String getContent();  
    3 }  

      FutureData,当有线程想要获取RealData的时候,程序会被阻塞。等到RealData被注入才会使用getReal()方法。

     1 package com.volshell.future;
     2 
     3 public class FutureData implements Data {
     4 
     5     protected RealData realData = null;
     6     protected boolean isReady = false;
     7 
     8     @Override
     9     public synchronized String getResult() {
    10         // TODO Auto-generated method stub
    11         while (!isReady) {
    12             try {
    13                 wait();
    14             } catch (Exception e) {
    15                 // TODO: handle exception
    16             }
    17         }
    18         return realData.result;
    19     }
    20 
    21     public synchronized void setRealData(RealData realData) {
    22         if (isReady)
    23             return;
    24         this.realData = realData;
    25         isReady = true;
    26         notifyAll();
    27     }
    28 }

      真实数据RealData

     1 package com.volshell.future;
     2 
     3 public class RealData implements Data {
     4     protected String result;
     5 
     6     public RealData(String para) {
     7         StringBuffer sb = new StringBuffer();
     8         for (int i = 0; i < 10; i++) {
     9             sb.append(para);
    10             try {
    11                 Thread.sleep(100);
    12             } catch (Exception e) {
    13                 // TODO: handle exception
    14             }
    15             result = sb.toString();
    16         }
    17     }
    18 
    19     @Override
    20     public String getResult() {
    21         // TODO Auto-generated method stub
    22         return result;
    23     }
    24 
    25 }

      客户端程序:

     1 package com.volshell.future;
     2 
     3 public class Client {
     4     public Data request(final String request){
     5         final FutureData future = new FutureData();
     6         new Thread(){
     7                 public void run() {
     8                     
     9                     RealData reaData = new RealData(request);
    10                     future.setRealData(reaData);
    11                 };
    12         }.start();
    13         return future;
    14     }
    15 }

      调用者:

     1 package com.volshell.future;
     2 
     3 public class Main {
     4     public static void main(String[] args) {
     5         Client client = new Client();
     6         Data data = client.request("name");
     7         System.out.println("请求完毕!!");
     8         try {
     9             Thread.sleep(2000);
    10         } catch (Exception e) {
    11             // TODO: handle exception
    12         }
    13         System.out.println("获取的数据:" +data.getResult());
    14     }
    15 }

      调用者请求资源,client.request("name"); 完成对数据的准备

      当要获取资源的时候,data.getResult() ,如果资源没有准备好isReady = false;那么就会阻塞该线程。直到资源获取然后该线程被唤醒。

      今天又重新了解了future模式。

     1 package com.volshell.future2;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 import java.util.concurrent.Callable;
     6 import java.util.concurrent.ExecutionException;
     7 import java.util.concurrent.ExecutorService;
     8 import java.util.concurrent.Executors;
     9 import java.util.concurrent.Future;
    10 
    11 public class FutureTest2 {
    12     private static class Task implements Callable<String> {
    13         @Override
    14         public String call() throws Exception {
    15             // 模拟真实事务的处理过程,这个过程是非常耗时的。
    16             Thread.sleep(5000);
    17             return "call return ";
    18         }
    19     }
    20 
    21     public static void main(String[] args) throws InterruptedException,
    22             ExecutionException {
    23         List<Future<String>> futures = new ArrayList<Future<String>>();
    24         ExecutorService executorService = Executors.newCachedThreadPool();
    25 
    26         System.out.println("已经提交资源申请");
    27         for (int i = 0; i < 10; i++) {
    28             futures.add(executorService.submit(new Task()));
    29         }
    30 
    31         for (Future<String> future : futures) {
    32             // 判断资源是不是已经准备完毕,准备完毕直接获取。
    33             if (!future.isDone()) {
    34                 System.out.println("资源还没有准备好");
    35             }
    36             System.out.println(future.get());
    37         }
    38         executorService.shutdown();
    39     }
    40 }

    其中的核心就是Callable中的call方法,这个和Runnable中的run 非常类似。

    Runnable和Callable都是接口
    不同之处:
    1.Callable可以返回一个类型V,而Runnable不可以
    2.Callable能够抛出checked exception,而Runnable不可以
    3.Runnable是自从java1.1就有了,而Callable是1.5之后才加上去的
    4.Callable和Runnable都可以应用于executors。而Thread类只支持Runnable.
    上面只是简单的不同,其实这两个接口在用起来差别还是很大的。Callable与executors联合在一起,在任务完成时可立刻获得一个更新了的Future。而Runable却要自己处理

     

      Future接口,一般都是取回Callable执行的状态用的。其中的主要方法:

    • cancel,取消Callable的执行,当Callable还没有完成时
    • get,获得Callable的返回值
    • isCanceled,判断是否取消了
    • isDone,判断是否完成

     

    用Executor来构建线程池,应该要做的事:

    1).调用Executors类中的静态方法newCachedThreadPool(必要时创建新 线程,空闲线程会被保留60秒)或newFixedThreadPool(包含固定数量的线程池)等,返回的是一个实现了ExecutorService 接口的ThreadPoolExecutor类或者是一个实现了ScheduledExecutorServiece接口的类对象。

    2).调用submit提交Runnable或Callable对象。

    3).如果想要取消一个任务,或如果提交Callable对象,那就要保存好返回的Future对象。

    4).当不再提交任何任务时,调用shutdown方法

  • 相关阅读:
    RBAC-实现不同用户拥有不同权限
    RBAC鉴权-通过聚合clusterrole实现集群权限控制
    kubernetes中Deployment和replicaset关系剖析
    常用php操作redis命令整理(四)SET类型
    LINUX 系统硬盘占满,找不到大文件,原来是进程问题
    c#使用System.Media.SoundPlayer播放资源文件中的wav文件
    Go语言中的并发安全和锁
    Go语言中的channel
    Go语言goroutine并发编程
    Sublime Text的这些快捷操作,你都会用吗
  • 原文地址:https://www.cnblogs.com/plxx/p/4574141.html
Copyright © 2011-2022 走看看