Java线程池ExecutorService

多线程概念和相关包:

线程池:提供一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁的额外开销,提高了响应的速度。

线程池的体系结构:
java.util.concurrent.Executor 负责线程的使用和调度的根接口
        |--ExecutorService 子接口: 线程池的主要接口
                |--ThreadPoolExecutor 线程池的实现类
                |--ScheduledExceutorService 子接口: 负责线程的调度
                    |--ScheduledThreadPoolExecutor : 继承ThreadPoolExecutor,实现了ScheduledExecutorService
            

工具类:Executors
ExecutorService newFixedThreadPool() : 创建固定大小的线程池
ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。
ExecutorService newSingleThreadExecutor() : 创建单个线程池。 线程池中只有一个线程

ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务

future:
在并发方面引入了Future这个概念。把所有不在主线程执行的代码都附加了将来这个灵魂。主线程只负责其它并发线程的创建、启动、监视和处理并发线程完成任务或发生异常时的回调。其它情况,则交给并发线程自己去处理。而双方之间的沟通,就是通过一个个被称之为 「 将来 」 的类出处理。
Future 定义在 java.util.concurrent 包中,这是一个接口,自 Java 1.5 以来一直存在的接口,用于处理异步调用和处理并发编程

例子:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


public class Main {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //1 创建线程池(执行器池)
        ExecutorService Executorspool = Executors.newFixedThreadPool(5);

        List<Future<Integer>> list=new ArrayList<Future<Integer>>();

        for (int i = 0; i < 10; i++) {
            // ---- 程序A ----
            Future<Integer>  future=Executorspool.submit(new Callable<Integer>() {
                public Integer call() throws Exception {
                    int sum=0;
                    for (int i = 0; i <=10; i++) {
                        //Thread.sleep(1000); 定义了5个执行器,这里开起了话将会看到效果
                        sum+=i;
                    }
                    return sum;
                }
            });
            // ---- 程序A ----
            list.add(future);
        }
        // 主线程,跟其他10个线程互不干扰
        System.out.println("Main Thread!!!");
        Executorspool.shutdown();
        for (Future<Integer> future : list) {
            // 打印结果数据
            System.out.println("Hello: "+future.get());
        }

    }
}

程序主要逻辑说明

程序A部分实际执行的计算是作为 Lambda 表达式参数传递给 call() 方法。这个实际执行的代码; Lambda 其实就是一个 Callable 实例,Callable 是一个接口,用于表示一个任务,这个任务可以返回值。Callable 接口只有一个方法 call();
Callable 实例创建完成后并不会立即执行,我们仍然需要将它传递给一个执行器( Executor , 执行程序 ) ,这个执行器将负责在新线程中启动该任务并返回一个包含了值的 Future 对象;这个执行器,是 Executor 的实例,通常,它是一个 ExecutorService 类的实例

ExecutorService Executorspool = Executors.newFixedThreadPool(5);
上面我们创建了一个能够处理5个线程的 ExecutorService,有了 ExecutorService 对象,调用它的 submit() 并传递 Callable 作为参数即可。 submit() 会启动任务并返回一个 FutureTask 对象。
FutureTask是一个类,实现了 Future 接口,在 java.util.concurrent 包中定义


Executorspool.shutdown(); 
此部分是关闭了提交通道submit() ,停止接收新任务,原来的任务继续执行;区别于shutdownNow():停止接受新任务,原来的任务停止执行;能立即停止线程池,正在跑的和正在等待的任务都停下

System.out.println("Hello: "+future.get());
打印结果,注意这个get方法是一个阻塞方法,如果任务 还没有执行完,那么会一直阻塞直到任务完成
为了防止阻塞,可以先用isDown()判断是否执行完
如果遇到长时间没有执行完的任务有两种处理方法:future.get(1000, TimeUnit.MILLISECONDS)
方法get(long, TimeUnit)是表示指定超时时间后任务仍未返回,那么就会抛出一个 TimeoutException
或者使用boolean canceled = future.cancel(true)方法取消Future

 改造上面例子,加入runnable和定时执行线程,另一个Java多线程extends Thread和implements Runnable文档:https://blog.csdn.net/jc_benben/article/details/106156747

主方法:

public static void main(String[] args)  {
        //1 创建线程池(执行器池)
        ExecutorService Executorspool = Executors.newFixedThreadPool(5);
        // 定时任务线程
        ScheduledExecutorService executorServiceScheduler = Executors.newSingleThreadScheduledExecutor();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                List<Future<Integer>> list=new ArrayList<Future<Integer>>();
                for (int i = 10; i < 12; i++) {
                    // ---- 程序A ----
                    System.out.println(i);
                    Future future=Executorspool.submit(new testCallable(i));
                    // ---- 程序A ----
                    list.add(future);
                }
                //Executorspool.shutdown();
                for (Future<Integer> future : list) {
                    // 打印结果数据
                    try {
                        //1s超时报错
                        System.out.println("Hello: "+future.get(1000, TimeUnit.MILLISECONDS));
                    }  catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        /*Thread thread = new Thread(runnable);
        thread.start();*/
        // 每5秒执行runnable 任务
        executorServiceScheduler.scheduleAtFixedRate(runnable,0,5000,TimeUnit.MILLISECONDS);
    }

 callable类:

import java.util.concurrent.Callable;

public class testCallable implements Callable {
    Integer initSum = 0;

    public testCallable(Integer initSum) {
        this.initSum = initSum;
    }

    @Override
    public Integer call() throws Exception {
        int sum=1000;
        /*for (int i = 0; i <=10; i++) {
            //Thread.sleep(1000); //定义了5个执行器,这里开起了话将会看到效果
            sum+=i;
            System.out.println("CurrentThread:"+Thread.currentThread());
        }*/
        System.out.println("CurrentThread:"+Thread.currentThread() +"-----> "+initSum);
        return sum + initSum;
    }
}

Runnable和Callable的区别:

Runnable执行方法是run(),Callable是call()
实现Runnable接口的任务线程无返回值;实现Callable接口的任务线程能返回执行结果
call方法可以抛出异常,run方法若有异常只能在内部消化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朝闻道-夕死可矣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值