1.Android 中的多线程
- 1.继承Thread
- 2.实现Runnable
- 3.Handler
- 4.AnsyTask
- 5.HandlerThread
ActivityThread 为 Android 主线程
2.AnsyTask
AsyncTask 最好在主线程中初始化。因为AsyncTask需要Handler来将执行结果回调切回主线程,Handler 中Looper.getMainLooper()。所以异步线程初始化也没关系
excute()最好在主线程中初始化。并且一个AsyncTask只能执行一次excute(),否则会报错。其内部有一个枚举类型的Status用于维护执行状态:PENDING、RUNNING、FINISHED。默认情况下是PENDING,表示可以执行,当调用execute方法之后,会检查其状态是否是PENDING,如果不是的话就会抛出异常。
经过测试。AsyncTask 可以在子线程初始化 和 excute() 可以在子线程中进执行
Android 1.6之前为串行,之后改为并行,3.0由改为串行。
execute()串行执行 —>调用executeOnExecutor(),并传入一个sDefaultExecutor(串行线程池)
sDefaultExecutor是SerialExecutor的一个实例,而且它是个静态变量。也就是说,一个进程里面所有AsyncTask对象都共享同一个SerialExecutor对象。
asyncTestThread.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,””); 并行执行最大5个线程。(固定线程数量的线程池)
AsyncTask.THREAD_POOL_EXECUTOR。也可以使用自己的线程池。
AsyncTask 中有两个线程池,SerialExecutor 和用于任务排队的线程池。
3.HandlerThread
- 继承自Thread,是一个子线程中创建了Handler
- HandlerThread 中run是无限循环,不需要时可以挂起,
- 在getLooper 中会try catch,避免looper为空
- 获取子线程创建Handler
|
|
4.ThreadLocal
ThreadLocal 存储器,做到只有该线程自己能够访问。就是多个线程访问同一份数据,每个线程得到数据不一致。理解为一个 Map,它的 set 和 get 方法都有一个“隐形的” key,那就是当前的线程对象,所以它才可以为每个线程保存一个数据副本。
5.IntentService
IntentService 继承自Service,并且是一个抽象类。IntentService封装了Handler和HandlerThread,所以这个Handler是子线程中的,适合执行耗时后台任务。
stopSelf(int startId) 会等任务执行结束后停掉服务,而stopSelf()会立即结束。
6.Handler
- 主线程创建
- Handler uiHandler = new Handler();
- Handler uiHandler = new Handler(Looper.getMainLooper());
- 创建子线程Handler
- Handler threadHandler = new Handler(mHandlerThread.getLooper());获取子线程Looper
- 原理,根据Looper找到关联的消息队列
子线程创建Handler,需要先进行 Looper.prepare()
|
|
7.继承Thread
|
|
8.Runnable
|
|
9. AsyncTask 示例
|
|
10.多线程的实现 or api 实现
线程池API分析
- 1.创建
- a.ThreadPoolExecutor.newFixedThreadPool();创建线程数量固定的线程池
- b.ThreadPoolExecutor.newSingleThreadExecutor();线程数固定为1的线程池
- c.ThreadPoolExecutor.newCachedThreadPool();会缓存的线程池,线程数量可以从0到Integer.MAX_VALUE,超时时间为1分钟。线程池用起来的效果是:如果有空闲线程,会复用线程;如果没有空闲线程,会新建线程;如果线程空闲超过1分钟,将会被回收。
- d. ThreadPoolExecutor.newScheduledThreadPool();将会创建一个可定时执行任务的线程池。
- 2.BlockingQueue
- newCachedThreadPool的线程上限几乎等同于无限,但系统资源是有限的,任务的处理速度总有可能比不上任务的提交速度。因此,可以为ThreadPoolExecutor提供一个阻塞队列来保存因线程不足而等待的Runnable任务,这就是BlockingQueue。
- 3.SynchronousQueue
- newCachedThreadPool使用的SynchronousQueue十分有趣,看名称是个队列,但它却不能存储元素。要将一个任务放进队列,必须有另一个线程去接收这个任务,一个进就有一个出,队列不会存储任何东西。因此,SynchronousQueue是一种移交机制,不能算是队列。newCachedThreadPool生成的是一个没有上限的线程池,理论上提交多少任务都可以,使用SynchronousQueue作为等待队列正合适。
- 4.饱和策略
- 当有界的等待队列满了之后,就需要用到饱和策略去处理,ThreadPoolExecutor的饱和策略通过传入RejectedExecutionHandler来实现。如果没有为构造函数传入,将会使用默认的defaultHandler。
- a.AbortPolicy是默认的实现,直接抛出一个RejectedExecutionException异常,让调用者自己处理。
- b.DiscardPolicy的rejectedExecution直接是空方法,什么也不干。如果队列满了,后续的任务都抛弃掉。
- c.DiscardOldestPolicy会将等待队列里最旧的任务踢走,让新任务得以执行。
- d.CallerRunsPolicy,它既不抛弃新任务,也不抛弃旧任务,而是直接在当前线程运行这个任务。当前线程一般就是主线程啊,让主线程运行任务,说不定就阻塞了。如果不是想清楚了整套方案,还是少用这种策略为妙。
- 5.线程池的执行
- 线程池是由Worker类负责执行任务,Worker继承了AbstractQueuedSynchronizer,引出了Java并发框架的核心AQS。
- worker在线程池里的四种可能(Worker在构造函数里采用ThreadFactory创建Thread,在run方法里调用了runWorker,看来是真正执行任务的地方。)
- 6.线程池的关闭
- shutdown:不能再提交任务,已经提交的任务可继续运行;
- shutdownNow:不能再提交任务,已经提交但未执行的任务不能运行,在运行的任务可继续运行,但会被中断,返回已经提交但未执行的任务。
- 7.Join、wait、notify、notifyAll、run()和start()
- Join()将改线程优先级提升,执行完后才可以执行其他线程。底层是利用wait()实现,主线程先获得了t对象的锁,t执行完成后,主线程继续执行,其他线程开始执行。
- 在 Java 中,可以通过配合调用 Object 对象的 wait() 方法和 notify()方法或 notifyAll() 方法来实现线程间的通信。在线程中调用 wait() 方法,将阻塞等待其他线程的通知(其他线程调用 notify() 方法或 notifyAll() 方法),在线程中调用 notify() 方法或 notifyAll() 方法,将通知其他线程从 wait() 方法处返回。
- run()和start()
- 1) start()
用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。 - 2)run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。这两个方法应该都比较熟悉,把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void。
- 1) start()
10.手写一个线程池
- 主要用 private BlockingQueue
taskQueue=new LinkedBlockingDeque (); 存储任务Runnable。 - //线程工作组,WorkerThread[] workThreads;存储初始化的线程
- taskQueue.take();// 获取并移除第一个元素 没有则扔进
|
|
HttpURLConnection
|
|