天天看點

android多線程之線程池

一.線程簡介

在Android應用開發中在進行耗時操作時,此時就要用到線程,由于UI線程不能進行耗時操作,否則就會造成ANR,話不多說下面直接幹貨。

二.子線程中更新UI的原理

有時在子線程中執行完操作以後需要把結果回傳到UI線程,但是由于異步操作,我們需要等待子線程執行完畢之後才更新UI,這時大家都會想到Handler ,Message這種消息傳遞機制進行線程的切換,

其中的源碼我在這裡不再的分析,但是線程切換最本質的地方如下代碼:

new Thread(new Runnable() {
            @Override
            public void run() {
                Looper looper = Looper.getMainLooper()
                looper.prepare();
                //執行UI操作
                looper.loop();
            }
        }).start();
           

其實Handle 消息機制最本質的就是利用Looper實作線程切換。

三.與多線程有關的方法

1.Callable

2.Future

3.FutureTask

4.Runnable

Runnable 在多線程中是最熟悉不過的,但是Runnable 和Future 可以應用在Thread中,而Callable和Future隻能應用線上程中。下面看代碼:

Runnable 接口

public interface Runnable {
    void run();
}
           

Runnable接口沒有傳回值

Callable 接口

public interface Callable<V> {
    V call() throws Exception;
}
           

Callable 接口與Runnable接口不同的是一個泛型接口,它有一個泛型V的call()方法的傳回值,而Runnable裡面的run()方法執行完沒有傳回值;

Future接口

public interface Future<V> {
    boolean cancel(boolean var1);
    //該任務是否取消
    boolean isCancelled();

    //該任務是否執行完成
    boolean isDone();

    //得到傳回結果,會發生阻塞
    V get() throws InterruptedException, ExecutionException;

    V get(long var1, TimeUnit var3) throws InterruptedException, ExecutionException, TimeoutException;
}
           

相比于Callable 和Runnable ,Future提供了對執行任務的可控性,這樣很大程度上友善對執行任務的操作。

FutureTask 類

public class FutureTask<V> implements RunnableFuture<V> {
    //代碼省略
}

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}
           

FutureTask 實作了Runnable,這就是為什麼他能應用于Thread中,下面我們通過一個例子來說明他們的差別!

public class FutureDemo {

    static ExecutorService mExecutor = Executors.newSingleThreadExecutor();

    public static void main(String[] args){
        testRunnable();
        testCallable();
        testFutureTask();

    }

    private static void testFutureTask() {
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return sum(, );
            }
        });
        mExecutor.submit(futureTask);
        try {
            System.out.println("=========testFutureTask====="+futureTask.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void testCallable() {
        Future<Integer> submit = mExecutor.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return sum(, );
            }
        });
        try {
            System.out.println("=========testCallable====="+submit.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private static void testRunnable() {
        Future<?> submit = mExecutor.submit(new Runnable() {
            @Override
            public void run() {
                sum(, );
            }
        });
        try {
            System.out.println("=========testRunnable====="+submit.get());
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    private static int sum(int a, int b){
        return a+b;
    }
}

下附輸出結果

=========testRunnable=====null
=========testCallable=====
=========testFutureTask=====
           

通過這個demo正好驗證上面的結果。

四.Android中的線程池

1.正常線程池

直接上代碼

public class ThreadManager {
    //線程池中線程數
    private final int THREAD_FIXED = ;
    //單例模式擷取對象
    private static ThreadManager sInstance = null;
    //線程池
    private ExecutorService mExecutorService;

    private ThreadManager() {
        this.mExecutorService = Executors.newFixedThreadPool(THREAD_FIXED);
    }

    public static synchronized ThreadManager getInstance() {
        if (sInstance == null) {
            sInstance = new ThreadManager();
        }
        return sInstance;
    }
    //執行操作任務接口
    public void submit(Runnable task) {
        this.mExecutorService.submit(task);
    }

    public Future<Integer> submit(Callable<Integer> task) {
        return this.mExecutorService.submit(task);
    }

    //關閉執行任務
    public void shutdown() {
        if (!this.mExecutorService.isShutdown())
            this.mExecutorService.shutdownNow();
    }
}
           

2.阻塞線程池

利用生産者和消費者模式來實作,并加上拒絕政策實作阻塞。直接上代碼。

public class ThreadPoolManager {

    //核心線程數
    private int corePoolSize = ;
    //最大線程數
    private int maximumPoolSize = ;
    //保持時間
    private long keepAliveTime =;
    //時間機關
    private TimeUnit unit = TimeUnit.SECONDS;
    //阻塞線程隊列
    private LinkedBlockingQueue<Runnable> workQueue =  new LinkedBlockingQueue<>();

    /**
     * 線程池,執行請求
     */
    private ThreadPoolExecutor threadPoolExecutor;

    private ThreadPoolManager(){
        this.threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        //開啟請求對列
        threadPoolExecutor.submit(runnable);
    }

    public static ThreadPoolManager getInstance(){
        return InstanceHolder.instance;
    }

    private static class InstanceHolder{
        private static ThreadPoolManager instance = new ThreadPoolManager();
    }

    /**
     * 暴露api,添加請求
     */
    public <T> void excute(FutureTask<T> futureTask){
       if(null != futureTask){
           try {
               workQueue.put(futureTask);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
    }

    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            while(true){
                FutureTask futureTask = null;
                try {
                    //阻塞就在這裡
                    futureTask = (FutureTask) workQueue.take();

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //執行請求
                    if(null != futureTask){
                        threadPoolExecutor.execute(futureTask);
                    }
                }

            }
        }
    };
    /**
     * 拒絕政策,實作隊列阻塞
     */
    private RejectedExecutionHandler handler = new RejectedExecutionHandler() {
        @Override
        public void rejectedExecution(Runnable runnable, ThreadPoolExecutor threadPoolExecutor) {
            try {
                workQueue.put(new FutureTask<Object>(runnable,null));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    };

}
           

下面是調用方法

ThreadPoolManager.getInstance().excute(new FutureTask<Object>(new Callable<Object>() {
            @Override
            public Object call() throws Exception {

                return null;
            }
        }));
           

執行流程如下:

1.建立ThreadPoolManager單例對象;

2.在構造方法裡面就建立線程并且執行任務Runnable

3.Runnable裡面就從隊列裡面取出任務,最後執行任務

4.excute()方法就是往隊列裡面添加任務.

到此android的線程池分析完畢;

逆風的方向,更适合飛翔