聪明出于勤奋,天才在于积累

  :: 首页 :: 博问 :: 闪存 :: 新随笔 :: :: :: 管理 ::

http://developer.android.com/training/multiple-threads/index.html

在多核CPU的手机上,线程可以并行,而不是竞争时间片,提高了效率。

1.在线程中运行一个任务

Thread、Runnable 是基础类,功能有限,但它们是 HandlerThread, AsyncTask, IntentService,ThreadPoolExecutor 等类的基础。

线程默认优先级是Norm的,和UI线程是一样的,所以工作线程的优先级应该降低。

//设置当前线程的属性为BACKGROUND,减少和UI线程竞争
public void run() {
    // Moves the current Thread into the background,在run方法中调用
    android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
}
 

//获取当前线程的对象
Thread.currentThread();

 

2. ThreadPoolExecutor 线程池

获取CPU的核数:

//获取可用的CPU核数,可能比物理的核数要少,比如为了省电关闭了一些
private static int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();

一般线程池的大小就是取这个核数的大小。

可以给 ThreadPoolExecutor 设置3种类型的队列:

1)SynchronousQueue,这种方式下不缓存任务,而是直接新建一个线程去执行,当线程数达到最大时,提交任务会失败。这种模式下 maximumPoolSizes 一般设为无限大。可能导致大量线程的创建。

2) 无限制的队列,比如大小无限制的  LinkedBlockingQueue,这种模式下的行为如下面详细叙述的。这种模式下 maximumPoolSize 其实是没用的,适用于任务短时大量增加,各任务相互独立的情况。

3) 有限制的队列,即缓存的队列大小有限制,一般将maximumPoolSizes设为无限大。这种情况比较难控制。

 

ThreadPoolExecutor 按队列来取任务去执行,要提供一个实现了BlockingQueue接口的队列(比如 LinkedBlockingQueue)。

这个队列里面存储的是,还在等待线程池空闲线程,来执行的任务,已经开始执行的任务已经被移除了。

 

创建线程池:

int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();

BlockingQueue
<Runnable> mDecodeWorkQueue = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor pool
= new ThreadPoolExecutor( NUMBER_OF_CORES, // Initial pool size NUMBER_OF_CORES, // Max pool size 1, TimeUnit.SECONDS, mDecodeWorkQueue); /* http://developer.android.com/reference/java/util/concurrent/ThreadPoolExecutor.html ThreadPoolExecutor 继承自 ExecutorService. public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue RejectedExecutionHandler handler); /*

当任务队列是 LinkedBlockingQueue 时的行为:

. 默认的时候,线程池是空的,当线程数小于corePoolSize 时,每提交一个任务就会创建一个新线程,即使这时候有空闲的线程。

. 当等待队列没有达到最大值时,线程最多只会创建corePoolSize个,新任务会等待执行,当队列满了不能再加入任务时,会新创建一个线程, 最多创建maximumPoolSize个线程,当线程数也达到最大值时,再加入任务,默认就会抛异常。(也就是说,当队列大小无限制时,线程数最多只有corePoolSize个,而maximumPoolSize参数是不起作用的)

. 当线程数大于corePoolSize, 空闲的线程在keepAliveTime 时间后就会释放,直到线程数达到corePoolSize。

.If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing. .If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread. .If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected

 

corePoolSize the number of threads to keep in the pool, even if they are idle

maximumPoolSize the maximum number of threads to allow in the pool

keepAliveTime when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.

unit the time unit for the keepAliveTime argument

workQueue the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.

handler the handler to use when execution is blocked because the thread bounds and queue capacities are reached 比如 mDecodeWorkQueue  = new LinkedBlockingQueue<Runnable>(3); 队列的大小是3,当队列里面有3个等待中的任务了, 再次调用 execute 往里添加任务时,就会抛异常。 这个参数可不提供,使用默认的。 */

 

可以预先创建好一些线程,而不是添加任务时才创建:  prestartCoreThread() 、 prestartAllCoreThreads()

默认的线程都在一个ThreadGroup中,优先级都是 NORM_PRIORITY,可以自己提供一个 ThreadFactory。

不调用shutDown或者shutdownNow,线程池中的线程会一直存在。
shutDown()会等到所有的任务都执行完毕,才将线程都结束掉。
shutdownNow 会将未执行的任务清除,并等到正在执行的任务结束,才将线程结束掉。

 

mDecodeWorkQueue.clear(); //清除未开始进行的任务

pool.execute(Runnable r); //加入一个任务,有空闲线程的时候就会开始执行

pool.shutDown();   
//调用shutDown后,不能再调用execute添加新的任务,否则会抛异常,已经添加的任务会继续按队列执行完毕。可以多次调用。
//Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation has no 
//additional effect if already shut down. This method does not wait for previously submitted tasks to complete execution. Use awaitTermination to do that. 

pool.shutdownNow();
//也不能再添加任务,而且队列中等待执行的任务会被清除,不会再执行,本方法会返回这些未执行任务的列表, 和shutDown还有个区别是,
//它会对工作的线程调用 interrupt();

pool.awaitTermination(5, TimeUnit.SECONDS); //阻塞当前线程,等待任务都完成,或者超时。

void shutdownAndAwaitTermination(ExecutorService pool) {
   pool.shutdown(); // Disable new tasks from being submitted
   try {
     // Wait a while for existing tasks to terminate
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
       pool.shutdownNow(); // Cancel currently executing tasks
       // Wait a while for tasks to respond to being cancelled
       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
           System.err.println("Pool did not terminate");
     
   } catch (InterruptedException ie) {
     // (Re-)Cancel if current thread also interrupted
     pool.shutdownNow();
     // Preserve interrupt status
     Thread.currentThread().interrupt();
   }
}

//是否允许core线程超时 (Added in API level 9)
public void  allowCoreThreadTimeOut (boolean value) 


//转换成数组,方便访问
Runnable[] runnableArray = new Runnable[mDecodeWorkQueue.size()];
mDecodeWorkQueue.toArray(runnableArray);

 

任务加入失败时,会调用  RejectedExecutionHandler 的 rejectedExecution(Runnable, ThreadPoolExecutor)方法,

1) 默认的 ThreadPoolExecutor.AbortPolicy 会抛一个 RejectedExecutionException 异常。

2) ThreadPoolExecutor.CallerRunsPolicy 用调用者的线程来执行这个任务。

3) ThreadPoolExecutor.DiscardPolicy, 简单的将任务丢弃

4) ThreadPoolExecutor.DiscardOldestPolicy 将队列头部的任务替换掉

 

可以重写两个回调方法:

beforeExecute(Thread, Runnable)

afterExecute(Runnable, Throwable)

 

getQueue()可以返回任务队列,但不建议直接去操作。  

 

一个pool如果没有被引用了,而且没有活动的线程了,即使没有调用 shutdown 也会被释放。

可考虑调用 allowCoreThreadTimeOut(boolean).

方法,这样即使core线程空闲的时候也会被结束掉,这样即使没有调用shutdown,pool也会释放。

 

 Executors 工厂方法提供了一系列创建线程池的方法,只是简单的对ThreadPoolExecutor的封装:

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, 
                                  Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
}

/*
public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor;

public ScheduledThreadPoolExecutor(int corePoolSize) {
     super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
              new DelayedWorkQueue());
}*/

 

 

 

 

 

 

 

 

 

 

 

posted on 2014-03-27 15:55    阅读(377)  评论(0)    收藏  举报