有关Java 5.0+ 并发包的探讨-2 section -补充-1

本文通过两个示例对比,详细解析了CompletionService如何确保异步任务的结果能够按照原始提交顺序获取。探讨了其内部实现机制,包括构造函数、submit方法及QueueingFuture类的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们现在来看看CompletionService

package ExecutorDemos;

import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ExecutorBasicDemo {

	public static void main(String[] args) throws InterruptedException,
			ExecutionException {
		//创建ExecutorCompletionService实例
		ExecutorService service=Executors.newFixedThreadPool(20);
		CompletionService<Object> serv = new ExecutorCompletionService<Object>(service);

		//创建50个工作
		for (int index = 0; index < 50; index++) {
			final int Position = index;  
			Callable<Object> dosomethings = new Callable<Object>() {
				public Object call() throws Exception {
					
					long value=(long) (Math.random() * 10000);
					System.out.println("Current sleep time is:"+value+", Position is "+Position);
					Thread.sleep(value);
					return value;
				}
			};
			serv.submit(dosomethings);
		}

		Thread.sleep(1000);
		for (int index = 0; index < 50; index++) {
			//按顺序取出来
			Future<Object> task = serv.take();
			Object value = task.get();
			System.out.println(value);
		}
		service.shutdown();
	}

}


执行的结果是:

 

 


你发现结果是按顺序取出结果的,而且可以看出它与Future有关系。在上一篇中,我们看过一个例子:

package ExecutorDemos;

 import java.util.ArrayList;  
 import java.util.List;  
 import java.util.Random;  
 import java.util.concurrent.*;  
 import java.util.concurrent.atomic.AtomicInteger;  
  
 public class FutureTaskTest {  
   
     private static AtomicInteger Count = new AtomicInteger(0);  
  
     @SuppressWarnings("unchecked")  
     public static void main(String args[]) {  
  
       ExecutorService es = Executors.newFixedThreadPool(10);  
         List<Future<Integer>> tasks = new ArrayList<Future<Integer>>();  
        for (int i = 0; i <= 10; i++) {  
        	final int iCount=i;
            FutureTask<Integer> futureTask = new FutureTask<Integer>(  
                     new Callable() {  
                       @SuppressWarnings("static-access")  
                         public Integer call() throws Exception {  
                             Thread.currentThread().sleep(  
                                     (new Random()).nextInt(1000));  
                             System.out.println("Postion is "+iCount);
                            return Count.getAndIncrement();  
                         }  
                     });  
             tasks.add(futureTask);  
             es.submit(futureTask);  
         }  
 
         Integer result = new Integer(0);  
        try {  
             for (Future<Integer> task : tasks) {  
                 result += (Integer) task.get();  
            }  
            es.shutdown();  
             System.out.println(result);  
        } catch (InterruptedException e) {  
             e.printStackTrace();  
        } catch (ExecutionException e) {  
            e.printStackTrace();  
       }  
     }  
 }  


其执行结果是:

从结果看,取数据的时候并不能保证结果数据按照其原始顺序提取!我们对比一下上面这两段代码,发现貌似只是按顺序提取数据的那个代码多了个ExecutorCompletionService,其他部分基本相同,这样我们可以解释ExecutorCompletionService它的作用了,那就是
异步的执行任务,并按原始任务的顺序取得结果! 从ExecutorCompletionService源代码来看:

其构造函数中

 public ExecutorCompletionService(Executor executor) {
        if (executor == null)
            throw new NullPointerException();
        this.executor = executor;
        this.aes = (executor instanceof AbstractExecutorService) ?
            (AbstractExecutorService) executor : null;
        this.completionQueue = new LinkedBlockingQueue<Future<V>>();
    }

  实例化了一个堵塞队列,那么用这个干什么用哪?接下来看看submit的实现吧:

  

 public Future<V> submit(Callable<V> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<V> f = newTaskFor(task);
        executor.execute(new QueueingFuture(f));
        return f;
    }

    public Future<V> submit(Runnable task, V result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<V> f = newTaskFor(task, result);
        executor.execute(new QueueingFuture(f));
        return f;
    }

   呵呵,上面的submit实现解释Runnable和Callable是如何转化成Future的,另外还使用了Executor.execute(new QueueingFuture(f))! 而QueueingFuture是ExecutorCompletionService的一个私有内部类,我们看看它的

实现:

  

 private class QueueingFuture extends FutureTask<Void> {

        QueueingFuture(RunnableFuture<V> task) {

            super(task, null);

            this.task = task;

        }

        //completionQueue是使用的外部类的属性,即ExecutorCompletionService中的属性

        protected void done() { completionQueue.add(task); }

        private final Future<V> task;

    }

   Executor.execute方法会自动调用done方法并将Future加入到堵塞队列中,知道了吧?就是在这里把外部的Runnable或者Callable转化过来的Future和堵塞队列建立的联系(加入队列)completionQueue的类型是LinkedBlockingQueue LinkedBlockingQueue表明它是一个Queue,这就意味着它的元素是按先进先出(FIFO)的次序进行存储的。以特定次序插入的元素会以相同的次序被取出--但根据插入保证,任何从空队列中取出元素的尝试都会堵塞调用线程直到该元素可被取出时为止。同样地,任何向一个已满队列中插入元素的尝试将会堵塞调用线程直到该队列的存储空间有空余时为止。

    对于take()方法的实现:

public Future<V> take() throws InterruptedException {
        return completionQueue.take();
    }

   可以明确看到take()时,是从堵塞队列中take(),这可以解释为什么ExecutorCompletionService可以保证结果安装原始顺序输出的了!对于堵塞队列,我将在后面的文章中讨论到.我们在了解其基本原理的基础上,才能很好的使用它,不是吗?
综上,如果您的应用对结果数据的顺序没有要求,你就可以使用FutureTask和ExecutorService! 如果有要求,最好使用CompletionService!

 

 

 

内容概要:本文详细探讨了杯形谐波减速器的齿廓修形方法及寿命预测分析。文章首先介绍了针对柔轮与波发生器装配时出现的啮合干涉问题,提出了一种柔轮齿廓修形方法。通过有限元法装配仿真确定修形量,并对修形后的柔轮进行装配和运转有限元分析。基于Miner线性疲劳理论,使用Fe-safe软件预测柔轮寿命。结果显示,修形后柔轮装配最大应力从962.2 MPa降至532.7 MPa,负载运转应力为609.9 MPa,解决了啮合干涉问题,柔轮寿命循环次数达到4.210⁶次。此外,文中还提供了详细的Python代码实现及ANSYS APDL脚本,用于柔轮变形分析、齿廓修形设计、有限元验证和疲劳寿命预测。 适合人群:机械工程领域的研究人员、工程师,尤其是从事精密传动系统设计和分析的专业人士。 使用场景及目标:①解决杯形谐波减速器中柔轮与波发生器装配时的啮合干涉问题;②通过优化齿廓修形提高柔轮的力学性能和使用寿命;③利用有限元分析和疲劳寿命预测技术评估修形效果,确保设计方案的可靠性和可行性。 阅读建议:本文涉及大量有限元分析和疲劳寿命预测的具体实现细节,建议读者具备一定的机械工程基础知识和有限元分析经验。同时,读者可以通过提供的Python代码和ANSYS APDL脚本进行实际操作和验证,加深对修形方法和技术路线的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值