一.線程簡介
在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的線程池分析完畢;
逆風的方向,更适合飛翔