JDK源码阅读(四):Future模式和Callable接口

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/aimomo007/article/details/89329336


Java多线程编程中,常用的多线程设计模式包括:Future模式、Master-Worker模式、Guarded Suspeionsion模式、不变模式和生产者-消费者模式。

Future模式核心思想

Future模式的核心在于:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑。

Future模式的基本原理

案例一:Java实现Future模式

Client.java:

public class Client {   
    public Data request(final String string) {    
        final FutureData futureData=new FutureData();     
        new Thread(new Runnable() {       
        
        @Override      
        public void run() {        
        	//RealData的构建很慢,所以放在单独的线程中运行,可以立即返回futureData   
        	RealData realData=new RealData(string);       		
        	futureData.setRealData(realData);      
        }    
        }).start();     
        return futureData;  
    } 
}

FutureData.java:作为RealData类的代理

public class FutureData implements Data<String>{  
	RealData realData = null; 
	//FutureData是RealData的封装  
	boolean isReady = false; //是否已经准备好   
	
	public synchronized void setRealData(RealData realData) {    
		if(isReady) {      
			return;    
		}
        
		this.realData=realData;    
		isReady=true;    
		notifyAll(); //RealData已经被注入到FutueData中了,通知getResult()方法 
	}   

	@Override  
	public String getResult() throws InterruptedException {    
		if(!isReady) {      
		wait();//一直等到RealData注入到FutureData中    
		}    
		return realData.getResult();  
	} 
}

RealData.java

public class RealData implements Data<String> {  
	protected String data;   
	public RealData(String data) {    
	// 利用sleep方法来表示真是业务是非常缓慢的    
	try {      
		Thread.sleep(1000);    
		} catch (InterruptedException e) {      
			e.printStackTrace();    
		}    
	this.data = data;  
	}   
	
	@Override  
	public String getResult() throws InterruptedException {    
		return data;  
	} 
}

Data.java

public interface Data<String> {   
	String getResult() throws InterruptedException; 
}

Application.java

public class Application {  
	public static void main(String[] args) throws InterruptedException, ExecutionException {    
	Client client = new Client();    
	//这里会立即返回,因为获取的是FutureData    
	Data data=client.request("name");    
	Thread.sleep(2000);    
	//使用真实数据    
	System.out.println("数据="+data.getResult());      
	}
}

案例二:JDK的内置Future实现

RealData.java

public class RealData implements Callable<String>{  
	protected String data;   
	public RealData(String data) {    
		this.data = data;  
	}   
	
	@Override  
	public String call() throws Exception {    
	//利用sleep方法来表示真是业务是非常缓慢的    
	try {        
		Thread.sleep(1000);    
	} catch (InterruptedException e) {        
		e.printStackTrace();    
	}    
	
	return data;  
	} 
}

Application.java

public class Application {  
	public static void main(String[] args) throws InterruptedException, ExecutionException {    
	FutureTask<String> futureTask=new FutureTask<>(new RealData("name"));    
	ExecutorService executorService=Executors.newFixedThreadPool(1);    	executorService.submit(futureTask);    
	Thread.sleep(2000);    
	//使用真实数据    
	//如果call()没有执行完成依然会等待    
	System.out.println("数据="+futureTask.get());  
	}
}

Callable、Future原理解析

Executor框架使用Runnable作为其基本的任务表示形式。Runnable中的run方法不会返回一个值或抛出一个受检查的异常。

扫描二维码关注公众号,回复: 5926469 查看本文章
public interface Runnable {    
	public abstract void run();
}

许多任务实际上都是存在延迟的计算,对于这些任务,Callable是一种更好的抽象:它的call方法会返回一个值,并且可能抛出一个异常。但实际上call底层还是调用了run方法,具体的细节在后面的线程池章节介绍。

public interface Callable<V> {    	
	/**     
	* Computes a result, or throws an exception if unable to do so.     
	* *     
	* * @return computed result     
	* * @throws Exception if unable to compute a result     
	* */    
	V call() throws Exception;
}

Runnable和Callable描述的都是抽象的计算任务。Executor执行的任务有四个阶段:创建,提交,开始和完成。由于有些任务可能要执行很长的时间,因此通常希望可以取消某些任务。在Executor框架中,已提交但尚未开始的任务可以取消,对于已经开始执行的任务,只有当它们响应中断时才能取消。

Future表示一个任务的生命周期,并提供了方法来判断是否已经完成或取消,以及获取任务的结果和取消任务等。

public interface Future<V> {    
	boolean cancel(boolean mayInterruptIfRunning);     
	boolean isCancelled();     
	boolean isDone();     
	V get() throws InterruptedException, ExecutionException;     
	V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}

在Future接口声明了5个方法:

  1. cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
  2. isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
  3. isDone方法表示任务是否已经完成,若任务完成,则返回true;
  4. get()方法用来获取call方法的执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
  5. get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。

猜你喜欢

转载自blog.csdn.net/aimomo007/article/details/89329336