JAVA多线程Future异步返回实现

Future基本知识不做介绍,主要是简单的实现方式

1.创建线程池

FixedThreadPool 与 CachedThreadPool 特性对比

特性 FixedThreadPool CachedThreadPool
重用 FixedThreadPool 与 CacheThreadPool差不多,也是能 reuse 就用,但不能随时建新的线程 缓存型池子,先查看池中有没有以前建立的线程,如果有,就 reuse ;如果没有,就建一个新的线程加入池中
池大小 可指定 nThreads,固定数量 可增长,最大值 Integer.MAX_VALUE
队列大小 无限制 无限制
超时 无 IDLE 默认 60 秒 IDLE
使用场景 所以 FixedThreadPool 多数针对一些很稳定很固定的正规并发线程,多用于服务器 大量短生命周期的异步任务
结束 不会自动销毁 注意,放入 CachedThreadPool 的线程不必担心其结束,超过 TIMEOUT 不活动,其会自动被终止。

 

 

 

 

 

 

 

 

 

最佳实践

FixedThreadPool 和 CachedThreadPool 两者对高负载的应用都不是特别友好。

CachedThreadPool 要比 FixedThreadPool 危险很多。

如果应用要求高负载、低延迟,最好不要选择以上两种线程池:

  1. 任务队列的无边界:会导致内存溢出以及高延迟
  2. 长时间运行会导致 CachedThreadPool 在线程创建上失控

因为两者都不是特别友好,所以推荐使用 ThreadPoolExecutor ,它提供了很多参数可以进行细粒度的控制。

  1. 将任务队列设置成有边界的队列
  2. 使用合适的 RejectionHandler - 自定义的 RejectionHandler 或 JDK 提供的默认 handler 。
  3. 如果在任务完成前后需要执行某些操作,可以重载

     beforeExecute(Thread, Runnable)
     afterExecute(Runnable, Throwable)
  4. 重载 ThreadFactory ,如果有线程定制化的需求
  5. 在运行时动态控制线程池的大小

 

创建共享的线程池,本实例使用了ThreadPoolExecutor 线程池

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CommonThreadPoolExecutor {

    public static final ThreadPoolExecutor futureThreadPool; // 并发共用线程

    static {


        //线程池维护线程的最少数量,核心线程数
        final int PARTNER_COREPOOLSIZE = 40;
        //线程池维护线程的最大数量
        final int PARTNER_MAXINUMPOOLSIZE = 200;
        //线程池维护线程所允许的空闲时间
        final long PARTNER_KEEPALIVETIME = 0;
        //线程池维护线程所允许的空闲时间的单位
        final TimeUnit PARTNER_UNIT = TimeUnit.SECONDS;
        //线程池所使用的缓冲队列,这里队列大小为20
        final BlockingQueue PARTNER_WORKQUEUE = new ArrayBlockingQueue(20);

        //线程池对拒绝任务的处理策略:AbortPolicy为抛出异常;CallerRunsPolicy为重试添加当前的任务,他会自动重复调用execute()方法;DiscardOldestPolicy为抛弃旧的任务,DiscardPolicy为抛弃当前的任务
        final ThreadPoolExecutor.CallerRunsPolicy PARTNER_HANDLER = new ThreadPoolExecutor.CallerRunsPolicy();
        futureThreadPool = new ThreadPoolExecutor(PARTNER_COREPOOLSIZE, PARTNER_MAXINUMPOOLSIZE, PARTNER_KEEPALIVETIME, PARTNER_UNIT, PARTNER_WORKQUEUE, PARTNER_HANDLER);
    }
}

 

2.业务实现

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class CommonService {

    public static void main(String[] args) {

        // 使用固定数量的线程池,避免高并发导致服务器线程无限制的增长
        ThreadPoolExecutor executor = CommonThreadPoolExecutor.futureThreadPool;

        try {
            // 主线程优先拿到最先完成的任务的返回值,而不管它们加入线程池的顺序。
            CompletionService completionService = new ExecutorCompletionService(executor);

            Future future = null;

            // 返回结果的集合
            List results = new ArrayList<>();

            // 需要并发处理的数据集
            String ids = "1,2,3";

            for (String pid : ids.split(",")) {

                final String id = pid;

                future = completionService.submit(new Callable() {

                    @Override
                    public Object call() {
                        // 处理实际业务
                        System.out.println(id);
                        // 返回处理的结果
                        return new Object();
                    }
                });

                // 等待返回结果
                results.add(future);
            }
            
            Object obj = null;
            for (Future fut : results) {
                // fut.get() 得到返回的结果
                obj = (Object)fut.get();
            }


        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}
 
  

 

注:使用线程能很大的提升相应速度,但需要谨慎使用,避免服务器压力过高

 

 

你可能感兴趣的:(JAVA)