浅析:Callable接口

189 阅读3分钟

这是我参与 8 月更文挑战的第 9天,活动详情查看: 8月更文挑战

**首先我们知道有两种创建线程的方法,一种是通过new Thread类,另一种是通过使用Runnable创建线程。**这是通常情况下的创建线程的方法,但是这两种并没有我们要的返回体,所以我们需要官方再给我们提供一个创建线程的接口-->callable,除了上面的返回体,还有异常的抛出也是runnnable无法提供的;

如何实现callable

既然这样我们就按现实项目来,先是创建任务线程池

ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();

设置完线程数、最大线程数、队列、空闲时间、拒绝策略后进行初始化

taskExecutor.initialize();

这里我设置的是线程数:3,最大线程数:5,队列:0,拒绝策略为交由主线程执行;

主(main)函数里执行

//线程池任务执行器初始化
            ThreadPoolTaskExecutor taskExecutor = getExecutor();
            for(int i = 0;i<100;i++){
                Future<Boolean> booleanFuture = taskExecutor.submit(new UserMessProcessHandle("xxx"+i));
                //booleanFuture.get();
            }

我循环一百次来调用它,别问为啥,问就是复习多线程;巩固学习,逻辑UserMessProcessHandle方法是:

public class UserMessProcessHandle implements Callable<Boolean> {
    private String note;
    public UserMessProcessHandle(String note) {
        this.note = note;     
    }

    @Override
    public Boolean call() throws InterruptedException {
        System.out.println(Thread.currentThread().getName()+"  "+note);
        Thread.sleep(1000);      
        //other逻辑
        return true;
    }
}

之所以睡眠一秒,是怕打出的日志不符合我的预期;我们看下输出:

pool-1  xxx0
pool-4  xxx3
pool-3  xxx2
pool-2  xxx1
pool-5  xxx4
main  xxx5
main  xxx6
pool-3  xxx7
pool-4  xxx8
pool-2  xxx11
main  xxx12

结果是符合预期的,默认三个线程,最大五个线程,拒绝就是main主线程执行,如果你放开booleanFuture.get(),那么他还会不停地打印true;这个的好处就是比如说你有批量对象要处理,处理过后你得要处理后的对象,那么你就可以将Future的类型变为你的对象类型,是不是觉得打开了一扇窗;

实现原理

用submit来处理是怎么处理的呢?首先他会通过ExecutorService来接收获取线程池执行器。然后调用executor.submit(task);来执行submit方法,我们看下官方对这个submit的解释;

提交一个返回值的任务以供执行,并返回一个表示任务结果的 Future。 Future 的get方法将在成功完成后返回任务的结果

顺藤摸瓜,我们再点进submit中我们看到AbstractExecutorService,这里的submit会执行通过RunnableFuture接收,创建返回一个RunnableFutur,他的对象会执行Execute方法,他的定义是在将来的某个时间执行给定的命令。 根据Executor实现的判断,该命令可以在新线程、池线程或调用线程中执行,

里面的参数是Runnable task,是不是似曾相识,是的,这里和runnable基本就是一样的了,下面有想法的同志可以继续往下探索了,基本逻辑就是这样,不停点进方法里,看实现方法和返回;