通过ANR来查看死锁

本文介绍如何在Android应用中使用ANR机制检测并分析死锁情况,通过生成traces.txt文件,开发者可以轻松定位到导致死锁的线程和代码片段。实例展示了DeadLockTraceActivity和ThreadDeadLockExample类的实现,以及如何手动触发死锁并生成对应traces.txt文件的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

死锁通常很难查找。但是在Android我们可以ANR来得到traces.txt。在traces.txt中可以查看那些线程在wait,当然死锁的线程也在其中。这样对查找死锁大大提供了方便。
注意:方式ANR后,在手机中就会生成如下文件data\anr\traces.txt
下面直接给出实例。
文件1
DeadLockTraceActivity.java文件
package com.gameloft.robin;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
public class DeadLockTraceActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.deadlock_trace);
    }
     String tag="robin";
  public void onResume()
    {
     super.onResume();
     new ThreadDeadLockExample().start();
     Handler handler=new Handler();
     Runnable run=new Runnable(){public void run(){forceWait();}};
     handler.post(run);     
    }
    synchronized void forceWait()
    {
     try {
wait(60000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
    }
}
文件2
ThreadDeadLockExample.java文件
package com.gameloft.robin;
import java.util.concurrent.locks.ReentrantLock;
import android.util.Log;
public class ThreadDeadLockExample{
    private final ReentrantLock lockA = new ReentrantLock(true);
    private final ReentrantLock lockB = new ReentrantLock(true);
    String tag="robin";
    void start()
    {
     Log.i(tag, "ThreadDeadLockExample start");
     new ThreadA("ThreadA").start();
     new ThreadB("ThreadB").start();
    }
    class ThreadA extends Thread
    {
     ThreadA(String name)
     {
     super(name);
     }
public void run()
{
Log.i(tag, "try to lock A"+" in ThreadA");
lockA.lock();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.i(tag, "lock A successful"+" in ThreadA");
Log.i(tag, "try to lock B"+" in ThreadA");
lockB.lock();
Log.i(tag, "lock B successful"+" in ThreadA");
lockB.unlock();
Log.i(tag, "unlock B"+" in ThreadA");
lockA.unlock();
Log.i(tag, "unlock A"+" in ThreadA");
}
    }
    class ThreadB extends Thread
    {
     ThreadB(String name)
     {
     super(name);
     }
public void run()
{
Log.i(tag, "try to lock B "+" in ThreadB");
lockB.lock();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.i(tag, "lock B successful"+" in ThreadB");
Log.i(tag, "try to lock A"+" in ThreadB");
lockA.lock();
Log.i(tag, "lock A successful"+" in ThreadB");
lockA.unlock();
Log.i(tag, "unlock A"+" in ThreadB");
lockB.unlock();
Log.i(tag, "unlock B"+" in ThreadB");
}
    }
}
traces.txt 文件摘要
DALVIK THREADS:
"main" prio=5 tid=1 TIMED_WAIT
  | group="main" sCount=1 dsCount=0 s=N obj=0x400208b8 self=0xcdf0
  | sysTid=1732 nice=0 sched=0/0 cgrp=unknown handle=-1345026000
  at java.lang.Object.wait(Native Method)
  - waiting on <0x4a5ba4b0> (a com.gameloft.robin.DeadLockTraceActivity)
  at java.lang.Object.wait(Object.java:326)
  at com.gameloft.robin.DeadLockTraceActivity.forceWait(DeadLockTraceActivity.java:24)
  at com.gameloft.robin.DeadLockTraceActivity$1.run(DeadLockTraceActivity.java:18)
  at android.os.Handler.handleCallback(Handler.java:587)
  at android.os.Handler.dispatchMessage(Handler.java:92)
  at android.os.Looper.loop(Looper.java:123)
  at android.app.ActivityThread.main(ActivityThread.java:4633)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:521)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
  at dalvik.system.NativeStart.main(Native Method)

"ThreadB" prio=5 tid=10 WAIT
  | group="main" sCount=1 dsCount=0 s=N obj=0x4a5bf868 self=0x2174f8
  | sysTid=1741 nice=0 sched=0/0 cgrp=unknown handle=2192952
  at java.lang.Object.wait(Native Method)
  - waiting on <0x4a5bf980> (a java.lang.VMThread)
  at java.lang.Thread.parkFor(Thread.java:1535)
  at java.lang.LangAccessImpl.parkFor(LangAccessImpl.java:48)
  at sun.misc.Unsafe.park(Unsafe.java:317)
  at java.util.concurrent.locks.LockSupport.park(LockSupport.java:131)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:790)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:823)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1153)
  at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:200)
  at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:261)
  at com.gameloft.robin.ThreadDeadLockExample$ThreadB.run(ThreadDeadLockExample.java:61)

"ThreadA" prio=5 tid=9 WAIT
  | group="main" sCount=1 dsCount=0 s=N obj=0x4a5bf438 self=0x216858
  | sysTid=1740 nice=0 sched=0/0 cgrp=unknown handle=2189720
  at java.lang.Object.wait(Native Method)
  - waiting on <0x4a5bf590> (a java.lang.VMThread)
  at java.lang.Thread.parkFor(Thread.java:1535)
  at java.lang.LangAccessImpl.parkFor(LangAccessImpl.java:48)
  at sun.misc.Unsafe.park(Unsafe.java:317)
  at java.util.concurrent.locks.LockSupport.park(LockSupport.java:131)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:790)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:823)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1153)
  at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:200)
  at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:261)
at com.gameloft.robin.ThreadDeadLockExample$ThreadA.run(ThreadDeadLockExample.java:35)
手动生成traces.txt文件
进入Android的shell命令行:
adb shell
得到app pid
$ps
发送信号
$kill -3 target_app_pid
检查 traces.txt 文件
$cd /data/anr
$ls -l
### 解决Android中的死锁ANR问题 #### 死锁解决方案 死锁通常发生在多个线程互相等待对方释放资源的情况下。为了防止这种情况的发生,可以采取以下措施: - **避免嵌套锁定**:如果可能的话,尽量减少在一个方法中同时获取多个锁的情况[^1]。通过分析Dalvik Debug Monitor Server的日志文件,能够定位到哪些线程正在持有锁并尝试获取其他锁。 - **按顺序加锁**:当需要多次调用不同对象上的同步方法时,应始终按照相同的顺序来获得这些对象的锁[^2]。 - **超时机制**:引入带超时参数的方法版本,在一定时间内无法成功取得所需资源则放弃当前操作并回滚状态[^3]。 以下是实现带有超时时限的`tryLock()`函数的一个简单例子: ```java import java.util.concurrent.locks.Lock; import java.util.concurrent.TimeUnit; public class TimeoutLockExample { private final Lock lock = new ReentrantLock(); public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException { return lock.tryLock(timeout, unit); } public void release() { lock.unlock(); } } ``` #### ANR(Application Not Responding)解决方案 ANR主要由主线程长时间阻塞引起,这可能是由于耗时计算放在UI线程上执行或者网络请求未及时返回等原因造成的。针对这一现象可以从以下几个方面入手优化程序性能: - **异步处理任务**:任何可能导致延迟的操作都应该放到后台线程去完成而不是直接运行于主线程之上。利用AsyncTask、HandlerThread或者是更现代的一些框架如RxJava/Kotlin Coroutines来进行并发编程可以帮助缓解这个问题。 - **监控响应时间**:定期检查是否有某个特定功能模块经常触发ANRs事件,并对其进行针对性改进。可以通过查看系统日志(`logcat`)以及崩溃报告工具捕获异常堆栈信息进一步缩小范围直至找到根本原因所在位置。 - **合理设置优先级**:对于那些不紧急但是又必须完成的任务降低它们相对于用户体验相关工作的调度级别从而让界面保持流畅度。 最后提醒开发者们注意的是即使解决了已知的所有潜在风险点也不能完全杜绝未来再次遭遇类似情况的可能性因此建议持续关注最新版SDK文档了解官方推荐的最佳实践不断调整自己的编码习惯适应新的变化趋势。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值