线程池提交同步或异步任务

2021-01-03  本文已影响0人  shiguangfeixu

提交Runnable任务

Runnable有一个run()函数,用于将耗时操作写在其中,该函数没有返回值。然后使用某个线程去执行该runnable即可实现多线程,Thread类在调用start()函数后就是执行的是Runnable的run()函数。

提交Callable任务,Future返回结果

Callable 在java 5中被引入, 作为Runnable 的一个对等(peer)。 Callable除了有一个Call 方法而不是Run 方法外(和Runnable)本质相同。 Call 方法有其它的能力去返回一个结果并且允许抛出检查时异常。

Callable 任务提交所产生的结果可用后能够被Future 获取,Future 可以被看作一个整理存储Callable 计算结果的容器。callable的计算能持续在另一个线程中, 并且任何获取一个Future 结果的尝试都将被阻塞,并且一旦(结果)变得可用,便会返回结果。

public interface Future<V>Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future<?> 形式类型、并返回 null 作为底层任务的结果。

public interface Callable<V>返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。

Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。

Runnable 提供了一种包裹要被在一个不同的线程中执行的代码的方式。它有一个缺陷, 不能从执行中返回结果。仅有的一种从一个Runnable 的执行中返回值的方式是把结果赋值给一个在Runnable 外部作用域中可访问的变量。

二者区别

Callable 和 Future接口的区别

使用案例

模拟任务

public class PollingResult {

    public Random random = new Random();

    public void executeTask(int sleepTime) {
        try {
            int value = random.nextInt(10);
            while(true){
                // 模拟轮询过程,随机耗时1-5s
                Thread.sleep(sleepTime);
                if ( value % 2 == 0) {
                    // 当前随机数是偶数直接结束循环
                    break;
                }
                value = random.nextInt(10);
            }
            System.out.println("SubmitRunnableTask:"+ value + "是偶数!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public Integer executeTask(int sleepTime, boolean callback) {
        try {
            int value = random.nextInt(10);
            while(true){
                // 模拟轮询过程,随机耗时1-5s
                Thread.sleep(sleepTime);
                if ( value % 2 == 0) {
                    // 当前随机数是偶数直接结束循环
                    break;
                }
                value = random.nextInt(10);
            }
            return value;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 0;
    }
}

提交Callback任务

public class SubmitCallableTask {
    /**
     * 构造一个并发数是5,阻塞队列是0,一满就抛异常的线程池
     */
    public static ExecutorService THREAD_POOL = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<>());

    public Random random = new Random(10);

    private PollingResult pollingResult = new PollingResult();

    public void execute() {
        Future<Integer> future = THREAD_POOL.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return pollingResult.executeTask(random.nextInt(1000), true);
            }
        });
        try {
            // get() 方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回
            System.out.println("SubmitCallableTask:"+future.get() + "是偶数!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

提交Runnable任务

public class SubmitRunnableTask {
    /**
     * 构造一个并发数是5,阻塞队列是0,一满就抛异常的线程池
     */
    public static ExecutorService THREAD_POOL = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<>());

    public Random random = new Random(10);

    private PollingResult pollingResult = new PollingResult();

    public void execute() {
        THREAD_POOL.submit(() -> {
            // 提交带执行的任务
            pollingResult.executeTask(random.nextInt(1000));
        });
    }
}

测试并发数

public class MainTask {

    private static SubmitRunnableTask submitRunnableTask = new SubmitRunnableTask();

    private static SubmitCallableTask submitCallableTask = new SubmitCallableTask();

    public static void main(String[] args) {
        // 提交异步任务,这个不会抛异常
        for(int i=0;i<10;i++){
            submitCallableTask.execute();
        }
        // 同时提交10个任务,肯定会抛异常
        for(int i=0;i<10;i++){
            submitRunnableTask.execute();
        }
    }
}

源码参考

线程池提交异步/同步任务

上一篇下一篇

猜你喜欢

热点阅读