作用
threadlist的runcheckpoint办法作用是让所有线程都执行制订的工作。threadlist的dump办法有两种实现形式:
1。打印调用者线程的栈帧状况
2。打印指定thread线程的栈帧状况。
依据下面两个函数置信大家能够猜到能够做哪些骚操作了。接下来持续解释
函数实现
runcheckpoint函数实现:
1。针对曾经在运行的线程只需对这个线程设置kcheckpoint标记位,运行中的线程查看到kcheckpoint会主动打印以后线程的信息。而针对不在运行的线程须要先设置suspendrequest标记位让他们暂停运行,避免之后暂停的线程状态变为运行。所以针对曾经运行的线程来说只有设置标记位即可,thread运行的时候会在特定指令处进行checkpoint办法进行查看标记位而作出对应的解决。
标记位品种:
1.kcheckpoint的标记位是取出本人tls区域的closure并执行指定run函数最多三个:通过tls区域保留 须要执行的run函数。run函数通过closure闭包封装。一个线程做多能够执行三个closure,也就是能够执行三个run办法。可通过add的形式进行增加对应线程tls区域的closure。
2.suspendrequest标记位是将线程状态设置为suspend暂停不运行。
解释:
threadlist中寄存着所有的线程也晓得所有运行的线程数是多少。
将所有线程都暂停怎么验证呢?
假如以后threadlist中有5个运行的线程数量通过suspendbarrier保留为5,我给所有的线程都设置ksuspendrequest标记位,当它们碰到某些指令时比方循环返回,异样指令处办法返回处等指令处时会运行runcheckpoint查看本人的标记位。而suspendrequest对应的第一步操作就是递加suspendbarrir而后挂起本人批改本人线程状态,当递加为0时代表所有线程都暂停了。这个时候就是所有线程都暂停。递加操作是无锁编程通过循环递加barrry,通过cas原子操作保障线程平安
如果要是不在运行的线程呢?就是说这个线程阻塞了或者曾经暂停了他都没有运行那么怎么进行查看标记位呢这个也就是下面说过的dump的第二种实现形式,不须要那个指定的线程运行本人打印本人线程的状况,而是通过调用者线程(你这个线程不运行,调用者线程运行我用调用者线程去打印)进行帮忙那些没有运行的线程打印信息,只须要指定对应的thread。
下面第一步设置ksuspendrequest标记位曾经让不在运行的线程都曾经进行运行了(即便暂停的线程复原运行也会在查看标记位的时候进行把本人暂停)而后我把一个执行dump函数的run函数封装成closure增加到threadlist中的每一个线程中。而dump函数是打印指定线程的栈帧信息。这里runcheckpoint都是通过指定线程的形式来打印对应指定线程的信息,执行线程是以后线程,然而打印对应线程状况的是指定的线程。
为什么呢?因为要保留线程不能产生任何内存上的变动所以只能通过将所有线程都suspend的形式实现,然而线程暂停了怎么可能打印本人的信息呢?所以得留一个活着的线程也就是以后线程去打印他们的信息
总结
查看标记位的操作之后就会查看到本人线程被设置了kcheckpoint标记位从tsl区域中取出closure执行工作;设置失败代表以后线程不在运行状态,那么也不能够间接打印那个线程的信息,因为之后这个线程可能再次运行会扭转线程的内存状况,所以针对暂停的线程还须要设置ksuspendpoint保障即便线程之后运行也会再次暂停(递加barrier胜利才会返回true),这样就能保障以后是产生状况的现场对应的状况。
思考环节
大家认真想想是不是咱们anr的时候查看trace文件会呈现一堆线程的信息不论是native的还是java的都会呈现。答案就是通过threadlist的runcheckpoint实现的。
运行的线程保障及时的打印过后虚拟机中所有线程状况,不在运行的线程设置挂起标记位保障即便运行也能保障不会毁坏现场。因为线程状态切换时也会进行一次标记位查看所以能够保障是之前那次收回指令时的内存状况。