最佳使用 Java 中的 Future 的方法

huangapple go评论69阅读模式
英文:

Best way to use Future in java

问题

我有一组作业,我正在使用执行器框架和Future来提交。假设我有100个Future。目前,我正在使用Future.get并使用输出进行后续处理。但为了进一步优化,我想改变流程如下:

  1. 遍历一组未来任务,并在未来任务完成后立即开始使用结果。我正在阅读API文档以了解如何更好地完成我所寻找的内容,但仍然想知道是否有更好的方法可以实现我所期望的目标。

以下是示例代码:

public class ImplCallable implements Callable<String> {
    	
    	int timeOut;
    	ImplCallable(int timeOut) {
    		this.timeOut=timeOut;
    	}
    	
    	public String call() throws Exception {
    		Thread.sleep(timeOut);
    		return Thread.currentThread().getName();
    	}
    
}

// 主类
public class MainProg {
    	public static void main(String...args) throws Exception {
    		long startTimeInMillis = System.currentTimeMillis();
    		ImplCallable callable1 = new ImplCallable(1000);
    		ImplCallable callable2 = new ImplCallable(2000);
    		
    		
    		ExecutorService service = Executors.newFixedThreadPool(4);
    		Future<String> task1 = service.submit(callable1);
    		Future<String> task2 = service.submit(callable2);
    		
    		List<Future<String>> futureList = new ArrayList();
    		futureList.add(task1);
    		futureList.add(task2);
    		
    		
    		String retVal;
    		for(Future<String> task:futureList) {
    			retVal = task.get();
    			// 使用retVal进行一些操作
    		}
    		long endTimeInMillis = System.currentTimeMillis();
    		
    		System.out.println("代码所用时间 - " + (endTimeInMillis-startTimeInMillis) + "-毫秒");
    	}
}

基本上,我不想使用**Future.get()**并等待其完成。我希望知道任何一个任务是否完成,并尽快使用结果。

英文:

I have a set of jobs which I am submitting using executor framework and Future. Let's say that I have 100 futures. As of now, I am using Future.get and using the output for subsequent processing. However for further tuning, I want to change the flow as below:

  1. iterate through the set of future tasks and start consuming the result as soon as a future task is complete. I am reading the API doc to understand what might be a good way to accomplish this but reaching out to see if there is a better way to accomplish what I am looking for.

Here is the sample code:

public class ImplCallable implements Callable&lt;String&gt; {
    	
    	int timeOut;
    	ImplCallable(int timeOut) {
    		this.timeOut=timeOut;
    	}
    	
    	public String call() throws Exception {
    		Thread.sleep(timeOut);
    		return Thread.currentThread().getName();
    	}
    
    }

and the main class:

public class MainProg {
    	public static void main(String...args) throws Exception {
    		long startTimeInMillis = System.currentTimeMillis();
    		ImplCallable callable1 = new ImplCallable(1000);
    		ImplCallable callable2 = new ImplCallable(2000);
    		
    		
    		ExecutorService service = Executors.newFixedThreadPool(4);
    		Future&lt;String&gt; task1 = service.submit(callable1);
    		Future&lt;String&gt; task2 = service.submit(callable2);
    		
    		List&lt;Future&lt;String&gt;&gt; futureList = new ArrayList();
    		futureList.add(task1);
    		futureList.add(task2);
    		
    		
    		String retVal;
    		for(Future&lt;String&gt; task:futureList) {
    			retVal = task.get();
    			//do something with the retVal
    		}
    		long endTimeInMillis = System.currentTimeMillis();
    		
    		System.out.println(&quot;time taken by code - &quot; + (endTimeInMillis-startTimeInMillis) + &quot;-ms&quot;);
    	}
    } 

Basically I don't want to use Future.get() and wait for its completion. I want to know if either of the task is complete and use the result as soon as its done.

答案1

得分: 2

有很多方法可以做到这一点,所以没有具体的示例,你不会得到具体的答案。可能需要查看 CompletableFuture,它有许多方法来定义后续工作、组合工作、拆分工作等。

Future&lt;String&gt; f = CompletableFuture.supplyAsync(() -&gt; &quot;INITIAL WORK&quot;)
  .thenApply(String::toLowerCase) // 进行更多工作
  .thenAccept(queue::add); // 将结果放入队列,某些东西正在从中读取

f.join();
// 批处理完成
英文:

There are many ways do this so, without a concrete example, you won't get a concrete answer. Likely want to look at CompletableFuture which has many methods for defining follow-on work, combining work, splitting work etc.

Future&lt;String&gt; f = CompletableFuture.supplyAsync(() -&gt; &quot;INITIAL WORK&quot;)
  .thenApply(String::toLowerCase) // Do some more work
  .thenAccept(queue::add); // put results onto a queue something is reading from

f.join();
// Batch complete

答案2

得分: 1

希望您正在使用Java 8或更高版本。
每当您提到“一旦未来的任务完成”,您想要使用CompletableFuture及其.thenApply()方法,正如@drekbour建议的那样。
然后,您有多个线程以非确定性顺序运行不同的任务。但最后,您希望在单个(主)线程中获取所有结果。为了实现这一点,您可以使用CompletableFuture.allOf方法,.join()它 - 然后迭代所有(已完成的)未来结果而无需等待。

英文:

I hope you are using Java 8 or later version.
Whenever you mention "as soon as a future task is complete", you want to use CompletableFuture and its .thenApply() method, as @drekbour suggests.

Then you have multiple threads running different tasks in non-determenistic sequence. But at the end you want to get all the results in the single (Main) thread. To achieve it, you can use CompletableFuture.allOf method, .join() it - and then iterate over all the (already completed) future results without waiting.

huangapple
  • 本文由 发表于 2020年7月30日 00:59:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/63158743.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定