MS
Handler
用于线程间通信,要素有handler, message, message queue, looper
子线程创建handler之前必须创建looper,looper prepare() 会 创建message queue
new handler时候会绑定到当前Thread中Threadlocal的looper
looper.loop的时候会开始轮训Meesage队列
发送消息调用messagequeue.enqueue()调用native方法唤醒让message.next()执行
取消息for(;;){message.next()}没有消息的话会调用Native方法 让出CPU,如果是主线程的话,
Activity没有事情做休眠也是可以的
一个线程可以创建多个handler,每个handler会放入message的target变量里面
一个looper可以对应多个handler.
匿名内部类会默认持有外部类的引用,所以要是用静态内部类,如果需要引用Actvity context,可以使用weakReference<>
软引用在内存不足的时候GC会被清理
弱引用GC就会清理
UI空间不支持多线程操作,而且加锁容易造成死锁,使UI逻辑复杂。
子线程textview.setText("")
https://baijiahao.baidu.com/s?id=1620358105307361783&wfr=spider&for=pc
Looper是保证Activity工作的循环操作,如果Looper退出的话ActivityThread就结束了,Activity的生命周期就是依靠looper来控制的,所以looper死循环不存在的,message.next()会调用native方法判断nativemessagequeue,为空的话让出CPU
会把消息根据时间顺序 插入messagequeue队列
不能,需要创建Looper使用looper.prepare(),或者直接使用handlerThread.
Message最好使用obtain方法,Obtain会从meesage pool中获取message,减少创建message的开销,这里使用的是享元模式式即:Flyweight,它是对象池的一种实现。享元模式用来尽可能的减少内存的使用量。多用于存在大量重复对象的场景,或需要缓冲池的时候。用来缓存共享的对象。这样来避免内存移除等。
每个Thread只有一个Looper实例,保存在ThreadLocal里面
自己不能new Looper实例,因为Looper构造方法是private的
在子线程中new handler时候传入主线程looper对象即可与主线程通信
AsyncTask就是对Handler的封装,有四个方法onprepare(主) doinbackground(子线程) onpostprogress(主) oncomplete(主)
线程
控制并发,管理线程(定时,单线程),快速执行减少创建和销毁的开销
newCachedThreadPool() 最大线程数Integer.MAX_VALUE 任务量大耗时少场景
newFixedThreadPool(int nThreads) 适用于任务量固定 且运行时间较长的场景 核心线程=最大线程不销毁 超过核心线程的任务阻塞在无界的LinkedBlockingQueue
ScheduledThreadPoolExecutor(int corePoolSize) 适用于执行定时任务和具体固定周期的重复任务 DelayedWorkQueue
newSingleThreadExecutor() 按顺序执行 LinkedBlockingQueue
参数有 核心线程数(一直存在不会销毁) 最大线程数 等待时间(超时销毁) 等待时间单位 线程队列 线程工厂 拒绝策略(抛异常或者抛弃新任务 丢掉老任务)
handler asynctask intentService Rxjava handlerThread
SerialExecutor(保证顺序执行)+ThreadPool(线程池 执行) +sHandler(主线程looper)
Service+handlerThread onhandleintent执行耗时任务 任务执行完自己关闭service
主线程创建thread一般是执行短暂的异步任务
service创建的thread一般是执行长期的任务 如长连接
1核心线程没满放入核心线程2队列没满放入队列3线程池没满创建线程池执行
Handler用于线程间通信,Thread用于开启并运行新线程,HandlerThread自己会创建Handler的Thread
threadlocal tl = new ThreadLocal();
Thread1{ tl.set(123)}
Thread2{tl.set(234)}
set的时候调用的是Thread内部的threadLocals.
不一定,主要用于异步操作把耗时任务放到后台,提高用户体验,多用于IO 网络 操作
缺点是线程太多造成CPU竞争,CPU需要不停切换线程,处理同步问题
懒汉双重检查加同步锁(懒加载)
饿汉(创建线程前已经建好)
还有notifayall(),notify只唤醒一个等待的线程,notifyall唤醒所有等待的线程,然后多个线程通过竞争得到锁
在生产消费者模式下,如果只唤醒一个进程的话可能
Activity5秒 broadcast 10秒 service 20秒 不要在主线程做耗时操作
查看data/anr trace
情景
1 binder调用导致anr,如果不需要返回值的话就在AIDL方法参数定义in(c-s)不需要等待返回
2 主线程等待锁,使用trylock解决
3 主线程做耗时操作
4 系统IO文件操作导致ANR,将文件操作放入子线程 ANRManager: 100% TOTAL: 2% user + 2.1% kernel + 95% iowait + 0.1% softirq
5 JE NE后系统dump信息导致ANR,解决JE NE即可
6 每个进程只分配15个binder线程,短时间大量binder调用可能导致超出的binder请求得不到处理
7 mokey可不处理
如果当前线程==获得锁的线程 则可以获取锁 锁count++, 释放一个锁的话count--,如果count ==0的话才释放
公平和非公平锁的队列都基于锁内部维护的一个双向链表,表结点Node的值就是每一个请求当前锁的线程。
公平锁则在于每次都是依次从队首取值。
非公平锁:在等待锁的过程中, 如果有任意新的线程妄图获取锁,都是有很大的几率直接获取到锁的。
线程池的七个参数为核心线程数,最大线程数,等待时间,等待时间单位,线程队列,线程工厂,拒绝策略
步骤1执行任务,如果核心线程满 进入队列,如果队列满,新建线程,如果超过最大线程的话 执行拒绝策略
常见线程池
固定线程池:核心线程等于最大线程,队列使用无边界的likedBlockQueue,适用于知道线程数,并且时间较长的任务
缓存线程池:大量耗时较少的任务
scheduledThreadPool:
singletonThreadPool:按顺序执行 不需要同步操作 要求顺序执行的任务如数据库操作 文件操作 应用安装
进程是应用的实体,一个应用至少有一个进程
线程是CPU调度的最小单元,App的主线程就是ActivityThread, 他里面的ApplicationThread是用来和AMS通信的binder.Activity启动后会有主线程和几个binder线程(用于AMS WMS通信)。
Handler asynctask rxjava handlerthread intentService
可以 子线程创建handler需要绑定Looper,绑定子线程looper需要使用looper.prepare() 然后用looper.loop()
也可以直接使用HandlerThread
线程池可以控制并发,减少新建/销毁线程的开销,可以控制线程执行间隔和执行顺序
7个参数 核心线程数 最大线程数 超时时间 超时时间单位 线程队列 线程工厂 拒绝策略
核心线程->队列->线程->拒绝策略
Thread+runnable, Thread(FutureTask(Callable)), asyncTask,handlerThread,rxjava
webView 大图 定位 push 不稳定操作(保护主线程)
可以使用更多内存,每个进程分配的内存固定,两个进程就可以拿到两倍内存
数据结构与算法
链表(遍历使用迭代器效率高) 数组 栈(先进后出) 队列(队尾入队 队首删除这点和栈不同) hashmap
sort(start, end)
{
int pivor = findPivot(start, end)
sort(start, pivot-1)
sort(pivot+1,end)
}
findPivot(){
while(){
while right--
while left++
}
}
swap(int a,int b)
1.7头插进链表,1.8尾插进链表,长度超过8数组不大于64先扩容
Bitmap
h*w*ARGB_8888(4)
LruCache DiskLRUcache
LinkedHashMap按访问排序,最新最近访问的放在链表尾端。
性能优化
会发生GC 回收内存
不考虑缩放的话 500*500*4/1024 = 976Kb
webview首次初始化耗时长,优化打开页面速度,创建全局webview,应用启动就创建webview实例
H5页面拉取优化,把html,css,js,image等资源预置在客户端本地预置在应用内部提高加载速度
webview加载图片最慢 可以先加载内容(setBlockNetworkImage(boolean)方法)然后再加载图片:在onPageStarted时屏蔽图片加载,在onPageFinished时开启图片加载。
设计模式
懒汉 恶汉
加锁是让多线程访问同步
两次判空,第一次判空是防止取锁 竞争是是防止排队中的线程创建多个实例
Java
Broadcast
Activity
Service
Android原理
进程间通信
网络
实际问题
基础
https://www.jianshu.com/p/ca2ecc3ea0f0
https://www.jianshu.com/p/81a17da4d695
作者:秀叶寒冬
链接:https://www.jianshu.com/p/c8dd2cb55b81
来源:简书
总结
- 上一篇: 平均值,方差计算(sss)
- 下一篇: 编程的精髓:发现问题,解决问题