线程的定义和状态
创建、就绪、运行、阻塞、停止
线程优先级
线程优先级的系统规则
线程是具有优先级的,高优先级的线程有更多CPU资源。
继承-线程优先级具有继承性,如果ThreadA启动了ThreadB,B默认具有和A一样的优先级。(this.priority = parent.getPriority();)
设置-优先级可以手动设置。
并行-高优先级的线程能获得更多CPU资源,但是低优先级的线程也能继续工作,高优先级并不会先执行
随机-高优先级的线程并不一定先执行,执行顺序是随机的。
线程优先级的设置
Thread和HandlerThread设置优先级的方式不一样。
Thread中线程优先级范围是1~10,数值越高,优先级越高,默认是5。
java.lang.Thread.setPriority(int i);
HandlerThread中线程优先级范围是-20~19,数值越低,优先级越高,默认为0。
android.os.Process.setThreadPriority(int p);
android.os.Process.setThreadPriority(int tid, int p);
HandlerThread还可以通过new HandlerThread("tname",-3)来设置。
在Thread或Runnable的run方法中,也可以通过Process.setThreadPriority设置优先级。
一般在实际应用中,通过Process设置优先级,对线程调度影响效果更明显,因为Process是android系统特别优化过的,是native的方法。
线程操作
同步
同步方式:synchronized和lock
同步相关方法:wait()/notify()/notifyAll() sleep()/join()/yield() await()/signal()/signalAll
常用的线程类
Thread和HandlerThread
在使用场景上,HandlerThread更节省资源:
如果多次调用new Thread(){...},会创造多个匿名线程,销毁资源
使用HandlerThread,是通过Looper缓存任务,重用线程,节省资源开销
Thread、Runnable和Callable
Runnable是个接口,实现更加灵活,而且一个Runnable的实例可以被多个Thread复用
线程池
线程池可以节约创建和销毁线程的资源开销。
- 线程池常见的几个类的用法:
ThreadPoolExecutor、Executor,Executors,ExecutorService,CompletionService,Future,Callable 等 - 线程池四个分类
newCachedThreadPool、newFixedThreadPool、newScheduledThreadPool和SingleThreadExecutor - 自定义线程池 ThreadPoolExecutor
线程池工作原理
核心线程数、等待队列、处理策略等
Handler、Thread和Runnable
Runnable是接口,可避免单继承局限,使用更灵活,且一个实例可以给多个thread共享。
Thread其实是一个对象,thread有thread.run()和thread.start()两种方法,run方法其实没有新建线程,而是在当前线程中直接执行;start才会真正创建一个线程,start带有synchronized同步锁,且一个nativeCreate的native方法去请求CPU,这个函数会把Thread自己的实例传进去,是c++实现的,sleep/interrupt等方法都是在这里实现的。
Handler是用来和Looper中的消息队列交互的,handler通过ThreadLocal获取Looper的MessageQueue,可以向queue中添加message,message的target又指向handler,这样Looper循环处理消息时,会把消息再交给handler去处理。
sleep() wait() join() yield()
sleep阻塞暂停,不释放锁和cpu
wait释放锁和cpu,需要被notify才能唤醒
join是暂停当前线程,先执行join进来的线程
yield是把当前线程设为可执行状态,给同等或更高优先级的其他线程一个执行机会,线程yield之后,很有可能继续恢复执行
引用
全面理解Java内存模型
Java多线程系列目录(共43篇)
Android开发——Android中常见的4种线程池(保证你能看懂并理解)
Handler、Thread和Runnable简单分析