线程池的一些东西

As everyone knows,线程池在java里就占有一定的分量,而这一点在Android上也有很广泛的应用。曾经无数次被问到过,什么是线程池,作用是什么?和线程的关系。是不是感觉头都大了,今天我就来整理一份关于线程池的一些内容。申明:此为个人学习总结part

1.什么是线程池?

理论上来说,线程池其实就是一个管理线程的地方。

2.为什么会有线程池这个东西的存在?

在以往的开发中我们需要子线程操作的时候,我们就随时随地的new一个Thread,或者弄一个Runnable来开启一个子线程,如果数量多了,以致于到处都是new的子线程,很多子线程空闲在那里,有些完成后又被GC,不停的GC,新建和闲置,造成浪费资源,还有可能会造成界面卡顿,对于线程的控制也很混乱。这个时候我们就可以用线程池,用线程池对项目的子线程进行管理和控制。

3.线程池的好处?

(a)线程的复用,重用已经创建好的线程,避免重复的创建和频繁的GC。

  (b) 控制线程并发数,合理使用系统资源。

  (c)可以有效控制线程的执行。定时执行,取消执行等操作。

探索线程池的用法

我们大概知道了线程池的作用和优点,接下来让我们了解一下它的一些类,一些方法,一些参数的意思。

1.ThreadPoolExecutor:它的构造方法有4种。这里挑最多参数的那组来说一下,因为最多的已经包含了其他的构造器里的参数。参数如下:

<a>corePoolSize 线程池中核心线程的数量

<b>maximumPoolSize 线程池中最大线程数量

<c>keepAliveTime 非核心线程的超时时长。在超过这个时间之后,非核心线程会被回收。若想在超时后回收核心线程,就设置ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,则这个参数也表示这个核心线程的超时时长。

<c>unit 第三个参数的单位

<d>workQueue 线程池中的任务队列(和Handler的MessageQueue有点相似),这里面存储的都是那些通过ThreadPoolExecutor的execute提交的任务,这些任务是已经提交但是还未执行的那些任务。

<e>threadFactory 为线程池提供创建新线程的功能。

<f>handler 

这个workQueue是一个BlockingQueue类型(阻塞队列).

而BlockingQueue又有如下类型:

(1)ArrayBlockingQueue:表示规定大小的BlockingQueue,存储在此的数据是先进先出(FIFO原则)

(2)LinkedBlockingQueue:表示大小不确定的BlockingQueue,LinkedBlockingQueue的构造函数里面有一个int值,给这个int一个值,那么代表这个LinkedBlockingQueue是有大小的。如果不给值,默认则是Interger.MAX_VALUE.

(3)priorityBlockingQueue:和LinkedBlockingQueue类似,但是它不是FIFO原则。它是由Comparator来决定存取顺序的(比如说按照年龄,身高排序)

(4)synchronousQueue:它是线程安全的BlockingQueue,它内部没有数据缓存空间。它的理解较为抽象,我们不能遍历读取其中的数据,而是存入和取出的时候会走SynchronousQueue过一下,所以说,在取走的时候这个数据此时才在队列里面存在一下。

你一定还想知道线程放到线程池之后是怎么去运行的呢?

前提都是在execute一个线程之后.......

(1)线程池的线程数<核心线程数,会立刻启用一个核心线程去执行

(2)线程池的线程数=核心线程数,而workQueue未满,则将新线程放入workQueue中等待执行。

(3)线程池的线程数=核心线程数,但是<非核心线程数,而workQueue已满,则开启一个非核心线程来执行任务。

(4)线程池的线程数>非核心线程数,则拒绝执行该任务。

接下来介绍几种线程池的类型

FixedThreadPool:核心线程数固定的线程池。

private void mFixedThreadPool(){
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    for(int i=0;i<30;i++){
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(3000);

            }
        };
        executorService.execute(runnable);
    }
}

结果是:首先就在核心线程添加3个任务0,1,2的任务。然后再添加任务在workQueue,若核心线程有空了,就会来处理workQueue任务队列的任务。

singleThreadPool:核心线程数只有1条。但使用它可以避免去处理线程同步问题。

private void mSingleThreadPool(){
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    for(int i=0;i<30;i++){
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(3000);

            }
        };
        executorService.execute(runnable);
    }
}

结果是:首先就核心线程添加1个0的任务。然后再添加任务在workQueue里....

CachedThreadPool:根据程序运行自动调整线程池中的线程数量。最大为Interger.MAX_VALUE.所以它适合大量任务请求的时候。CachedThreadPool中没有新任务的时候,里面的线程会因为超时而被终止。

private void mCachedThreadPool(){
    ExecutorService executorService = Executors.newCachedThreadPool();
    for(int i=0;i<30;i++){
        Runnable runnable=new Runnable() {
            @Override
            public void run() {

            }
        };
        executorService.execute(runnable);
        SystemClock.sleep(3000);//每隔3s在添加新任务。以致于之前的线程又空闲了,所以执行任务的应该都是那一个线程。
    }
}

ScheduledThreadPool:具有定时定期执行任务功能的线程池。核心线程数是固定的,但非核心线程数是无穷大的,所以在非核心线程闲置的时候会立即被回收。

(1)延迟启动任务

//延迟启动任务
private void mDelayScheduledThreadPool(){
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
        Runnable runnable=new Runnable() {
            @Override
            public void run() {

            }
        };
    executorService.schedule(runnable,2, TimeUnit.SECONDS);
}

(2)延迟定时执行任务

//延迟定时执行任务
private void mTimeScheduledThreadPool(){
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
    Runnable runnable=new Runnable() {
        @Override
        public void run() {

        }
    };
    executorService.scheduleAtFixedRate(runnable,1,1,TimeUnit.SECONDS);
}

延时1s后,每隔1s执行一个新任务。

(3)延迟执行任务

//延迟执行任务
private void mTime2ScheduledThreadPool(){
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
    Runnable runnable=new Runnable() {
        @Override
        public void run() {

        }
    };
    //第一次延迟1s,以后每次也延迟一秒执行
    executorService.scheduleWithFixedDelay(runnable,1,1,TimeUnit.SECONDS);
}

在线程池里面还有很多其他的比较常用的方法。

submit:一般情况我们用execute来提交任务,但是有的时候我们还会用到submit,因为submit有返回值

如下所示,callable接口实现异步任务,在call方法中来执行异步任务,那么突然要问一句,返回值是什么呢?你一定会有的懵逼,酱酱酱~其实返回值就是该任务的返回值

你是不是要问我Future是什么?哎呀,其实Future就是返回结果,返回他的isDone属性表示异步任务执行成功。

private void mSubmint(){
    List<Future<String>> futures=new ArrayList<>();
    ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(3,5,1,TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>());
    for(int i=0;i<10;i++){
        Future<String> taskFuture=threadPoolExecutor.submit(new MyTask(i));
        futures.add(taskFuture);
    }

    //遍历所有任务的结果
    for(Future<String> future:futures){
        try {
            Log.i("mylog","future="+future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}

class MyTask implements Callable<String>{

    private int taskId;

    public MyTask(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public String call() throws Exception {
        SystemClock.sleep(1000);
        //返回每一个任务的执行结果
        return "TaskName="+Thread.currentThread().getName()+"//TaskId="+taskId;
    }
}

除了使用submit可以让执行的任务有返回值之外,还有一种方式。那就是-----自定义线程池。

自定义线程池,那么那就是自定义ThreadPoolExecutor.

//自定义线程池
private void customThreadPool(View view){
    MyThreadPool myThreadPool=new MyThreadPool(3,5,2000,TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>());
    for(int i=0;i<10;i++){
        final int finalI=i;
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(1000);
                Log.i("myLog","finalId="+finalI);
            }
        };
        myThreadPool.execute(runnable);
    }
}

class MyThreadPool extends ThreadPoolExecutor{

    public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        Log.i("myLog","开始执行任务");
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        Log.i("myLog","任务执行结束");
    }

    @Override
    protected void terminated() {
        super.terminated();
        Log.i("myLog","线程池关闭");
    }
}

猜你喜欢

转载自blog.csdn.net/sweet_smile5/article/details/80227513