线程池简单案例


线程池创建方式

一、Executors

1、newFixedThreadPool

1.1 创建固定大小的线程池。
1.2 创建方式:ExecutorService fixedTp= Executors.newFixedThreadPool(int count);
1.3 适用场景:执行长期的任务

2、newCachedThreadPool

2.1 创建一个不限线程数上限的线程池,任何提交的任务都将立即执行
2.2 创建方式:ExecutorService cachedTp = Executors.newCachedThreadPool();
2.3 适用场景:执行很多短期异步的小程序或者负载较轻的服务器	

3、newSingleThreadExecutor

3.1 创建只有一个线程的线程池,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行		
3.2 创建方式:ExecutorService SingleTp = Executors.newSingleThreadExecutor();	
3.3 适用场景:一个任务一个任务执行的场景

4、newScheduledThreadPool

4.1 创建一个可定期或者延时执行任务的定长线程池,支持定时及周期性任务执行。
4.2 创建方式:ScheduledExecutorService schedTp= Executors.newScheduledThreadPool(5);
4.3 适用场景:周期性执行任务的场景
创建一个定长的线程池,线程池可以周期性或延迟执行如下:
 (1)  scheduledTp.schedule(r1, 5, TimeUnit.SECONDS);//延迟3秒后执行r1
 (2)  scheduledTp.scheduleAtFixedRate(r2,5,3,TimeUnit.SECONDS);//延迟5秒后每3秒执行一次r2

二、ThreadPoolExecutor

Executors创建线程池的快捷方法,实际上是调用了ThreadPoolExecutor的构造方法

 public ThreadPoolExecutor(
 int corePoolSize, // 线程池长期维持的线程数,即使线程处于Idle状态,也不会回收。
 int maximumPoolSize, // 线程数的上限
 long keepAliveTime, TimeUnit unit, // 超过corePoolSize的线程的idle时长,
                                    // 超过这个时间,多余的线程会被回收。
 BlockingQueue<Runnable> workQueue, // 任务的排队队列
 ThreadFactory threadFactory, // 新线程的产生方式
 RejectedExecutionHandler handler) // 拒绝策略
 
 举例:
 ExecutorService executorService = new ThreadPoolExecutor(2, 2, 0, TimeUnit.SECONDS, 
 new ArrayBlockingQueue<>(512), // 使用有界队列,避免OOM
 new ThreadPoolExecutor.DiscardPolicy());//DiscardPolicy 对溢出队列的任务不做处理,直接忽略
其他拒绝策略
AbortPolicy	 抛出RejectedExecutionException(默认)
DiscardOldestPolicy  丢弃执行队列中最老的任务,尝试为当前提交的任务腾出位置
CallerRunsPolicy	直接由提交任务者执行这个任务

三、两种线程池创建方式的异同

	1、Executors.newXXXThreadPool()快捷方法创建线程池,这种方式使用无界的任务队列,容易造成OOM
	建议使用ThreadPoolExecutor的构造方法手动指定各项参数。
	2、提交任务的类型分为Runnable和Callable 二者区别如下:
	 2.1 方法签名不同,void Runnable.run(), V Callable.call() throws Exception
	 2.2 是否允许有返回值,Callable允许有返回值
	 2.3 是否允许抛出异常,Callable允许抛出异常。
	提交任务的方式:
	Future<T> submit(Callable<T> task)	有返回值
	void execute(Runnable command)	无返回值
	Future<?> submit(Runnable task)	虽然返回Future,但是其get()方法总是返回null

四、返回值

1、获取单个结果
用submit()向线程池提交任务后会返回一个Future,Future.get()方法能够阻塞等待执行结果,
get(long  timeout, TimeUnit unit)方法可以指定等待的超时时间。

2、获取多个结果
如果向线程池提交了多个任务,要获取这些任务的执行结果,可以依次调用Future.get()获得。
对于这种场景,使用ExecutorCompletionService,该类的take()方法总是阻塞等
待某一个任务完成,然后返回该任务的Future对象。向CompletionService批量提交任务后,
只需调用相同次数的CompletionService.take()方法,就能获取所有任务的执行结果。

   List<Object>lists=new ArrayList<>();
   ExecutorService executorService = new ThreadPoolExecutor(2, 2, 0, TimeUnit.SECONDS, 
   new ArrayBlockingQueue<>(512), // 使用有界队列,避免OOM
   new ThreadPoolExecutor.DiscardPolicy());
   CompletionService<Object> cs= new ExecutorCompletionService<Object>(executorService );
   for (Callable<Object> s : lists)// 提交所有任务
     cs.submit(s);
   int n = lists.size();
   for (int i = 0; i < n; ++i) {// 获取每一个完成的任务
       Object r = cs.take().get();
       if (r != null)
        //一些操作
   }

五、一个简单实例

模拟发送消息
public class ExecutorTest {
   
    //核心线程数
    int poolSize = Runtime.getRuntime().availableProcessors() * 2;
    //任务队列
    BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(512);
    //拒绝策略
    RejectedExecutionHandler policy = new ThreadPoolExecutor.DiscardPolicy();
     //创建线程池
    ExecutorService service = new ThreadPoolExecutor(poolSize, poolSize,
    0, TimeUnit.SECONDS, queue, policy);

public static void main(String[] args) {
    ExecutorTest pmt = new ExecutorTest();
    //待接收人
    List<Integer> receivers = new ArrayList<>();
    for (int i = 0; i < 100; i++) {
        receivers.add(i);
    }
    String content = "群发消息_测试代码";
    int successCount = pmt.sendMsg(receivers, content); //使用线程池处理发送任务
    System.out.println("共有[" + receivers.size() + "]接收者,发送成功["+successCount+"]");
}

public int sendMsg(List<Integer> data, String content) {
        long begin = System.nanoTime();//开始时间
        AtomicInteger ai = new AtomicInteger(0);//原子性计数
        // 获取多个返回结果
        CompletionService<Integer> ecs = new ExecutorCompletionService<>(service);
        //循环发送消息
        for (int i = 0, len = data.size(); i < len; i++) {
            Integer dataReceiver = data.get(i);
            ecs.submit(() -> {
                //模拟调用相对比较耗时的发送消息接口
                Thread.sleep(100);
                //发送消息
                int result = sendMsg(dataReceiver, content);
                System.out.println("接收者["+dataReceiver + "], 执行结果["+result+"]");
                return result;
            });
        }
        System.out.println("-----" + (System.nanoTime() - begin) / 1000_000d + "-----");
        //循环获得执行结果
        int length = data.size();
        for (int i = 0; i < length; i++) {
            try {
                int resultStatus = ecs.take().get();
                if (resultStatus == 0) { //发送成功
                    ai.incrementAndGet();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    System.out.println("发送消息结束,耗时:" + (System.nanoTime() - begin) / 1000_000d);
    service.shutdown();//关闭线程池
        try {
            if (!service.awaitTermination(30, TimeUnit.SECONDS)) {
                System.out.println(" 到达指定时间,还有线程没执行完,不再等待,关闭线程池!");
                // 调用 shutdownNow 取消正在执行的任务
                service.shutdownNow();
                // 再次等待 60 s,如果还未结束,可以再次尝试,或则直接放弃
                if (!service.awaitTermination(60, TimeUnit.SECONDS))
                    System.err.println("线程池任务未正常执行结束");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return ai.get();//返回成功发送的次数
    }

//完成发送消息
private int sendMsg(Integer receiver, String content) {
    if (receiver % 2 == 0) {//模拟被2整除,即为发送成功
        return 0;
    }
    return 1;
}
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值