多线程 (2) ThreadPoolExecutor 介绍和 FutureTask使用

FutureTask是一种可以取消的异步的计算任务。它的计算是通过Callable实现的,并且有三个状态:等待、运行和完成。完成包括所有计算以任意的方式结束,包括正常结束、取消和异常。

 

 

V 	get()
          如有必要,等待计算完成,然后检索其结果。
 V 	get(long timeout, TimeUnit unit)
          如有必要,最多等待为使计算完成所给定的时间之后,检索其结果(如果结果可用)。
 

Executor框架利用FutureTask来完成异步任务,并可以用来进行任何潜在的耗时的计算。一般FutureTask多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。

 

 

public class TestFutureTask {

    /**
     * @param args
     * @create_time 2011-6-24 下午03:41:57 
     */
    public static void main(String[] args) {
        //创建线程池
        ThreadPoolExecutor pool=new ThreadPoolExecutor(3,3,2,TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(10),new ThreadPoolExecutor.AbortPolicy());
        List<FutureTask<String>>  tasks=new ArrayList<FutureTask<String>>();
        for(int i=0;i<10;i++){
            FutureTask<String> futureTask=new FutureTask<String>(new ThreadPoolTask(i));
            pool.submit(futureTask);
            tasks.add(futureTask);
        }
        for (FutureTask<String> futureTask : tasks) {
            try {
                //阻塞一直等待执行完成拿到结果
                System.out.println("future result:"+futureTask.get());
                //阻塞一直等待执行完成拿到结果,如果在超时时间内,没有拿到则抛出异常
//                System.out.println("future result:"+futureTask.get(1,TimeUnit.SECONDS));
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } //捕获超时异常
//            catch (TimeoutException e) {
//                e.printStackTrace();
//            }
        }
    }
    /**
     * 执行业务计算
     * 
     * @date 2011-6-24
     * Copyright (C) 2010-2012 www.2caipiao.com Inc. All rights reserved.
     */
    public static class ThreadPoolTask implements Callable<String>{

        private int value;
        
        public ThreadPoolTask(int value){
            this.value=value;
        }
        @Override
        public String call() throws Exception {
            //计算
            System.out.println("value-----"+value++);
            Thread.sleep(2000);
            return String.valueOf(value);
        }
        
    }
}
 

 

线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为:

 

 

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
 
 
corePoolSize: 线程池维护线程的最少数量
maximumPoolSize:线程池维护线程的最大数量
keepAliveTime: 线程池维护线程所允许的空闲时间
unit: 线程池维护线程所允许的空闲时间的单位
workQueue: 线程池所使用的缓冲队列
handler: 线程池对拒绝任务的处理策略
 

 

 

 

当一个任务通过execute(Runnable)方法欲添加到线程池时:
 
  如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
  如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
  如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
  如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
  当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。
 
unit可选的参数为java.util.concurrent.TimeUnit中的几个静态属性:
NANOSECONDS、
MICROSECONDS、
MILLISECONDS、
SECONDS。
 

 

 

workQueue常用的是:java.util.concurrent.ArrayBlockingQueue
 
handler有四个选择:
ThreadPoolExecutor.AbortPolicy()
抛出java.util.concurrent.RejectedExecutionException异常
 
ThreadPoolExecutor.CallerRunsPolicy()
重试添加当前的任务,他会自动重复调用execute()方法
 
ThreadPoolExecutor.DiscardOldestPolicy()
抛弃旧的任务
 
ThreadPoolExecutor.DiscardPolicy()
抛弃当前的任务
 

 


好的,我可以为你解答这个问题。 首先,你需要创建一个线程池,可以使用Java提供的ThreadPoolExecutor类。然后,你需要将任务封装成FutureTask对象,并将其添加到线程池中。 在这个例子中,我们假设有一个名为list的列表,需要使用多线程方式读取。以下是实现代码: ``` import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; public class MultiThreadListReader { public static void main(String[] args) { // 创建一个包含5个线程的线程池 ExecutorService executor = Executors.newFixedThreadPool(5); // 创建一个列表 List<Integer> list = new ArrayList<>(); for (int i = 0; i < 100; i++) { list.add(i); } // 创建一个FutureTask列表 List<FutureTask<List<Integer>>> taskList = new ArrayList<>(); // 将任务封装成FutureTask对象,并添加到列表中 for (int i = 0; i < 5; i++) { final int startIndex = i * 20; FutureTask<List<Integer>> task = new FutureTask<>(new Callable<List<Integer>>() { @Override public List<Integer> call() throws Exception { List<Integer> subList = new ArrayList<>(); for (int j = startIndex; j < startIndex + 20; j++) { subList.add(list.get(j)); } return subList; } }); taskList.add(task); executor.submit(task); } // 等待所有任务完成,并将结果合并 List<Integer> result = new ArrayList<>(); for (FutureTask<List<Integer>> task : taskList) { try { result.addAll(task.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } // 打印结果 System.out.println(result); // 关闭线程池 executor.shutdown(); } } ``` 在这个例子中,我们创建了一个包含5个线程的线程池,将列表分成5份,每份20个元素,每个线程负责读取其中一份元素,并将结果存入子列表中。最后,我们将所有子列表合并成一个结果列表,并打印出来。 注意,我们使用FutureTask对象来封装任务,并且通过调用get()方法来获取任务的结果。同时,我们也需要处理可能出现的InterruptedException和ExecutionException异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值