http://cwh528.blog.sohu.com/169639438.html
项目中碰到问题,涉及到主线程和子线程的通信和同步问题,测试中发现死锁情况,记录一下
void Main(){
ThreadB Threadb = new ThreadB();
Threadb .start();
synchronized (handler) {
try {
Log.e("sync_ThreadManager", "hold_Handeler");
handler.wait();
Log.e("sync_ThreadManager", "wait_Handeler");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
ThreadB extends Thread
{
public void run() {
Looper.prepare();
bHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//do something here
}
};
synchronized (handler) {
handler.notify();
}
Looper.loop();
}
}
上述代码设计意图是:红色代码执行的时候,启动另外一个线程,主线程先执行到蓝色部分(wait),此时,wait函数会导致主线程处于suspend状态,并且释放所hold的同步对象锁handler。此后子线程threadb获得同步锁handler,threadb初始化完毕,调用notify方法通知调用wait的线程,然后主线程会重新请求同步锁,如果成功则继续执行wait后面的代码,这个过程确保了子线程threadb的bhandler成功初始化,以后主线程main可以通过bhandler和子线程进行通信。大多情况下程序运行正常。但是多线程情况下并不能保证这个顺序,可能出现假死。
正常情况如下:
1.Main 执行到synchronized (handler) ,抢先获得handler锁对象
2.vm切换执行threadb,执行到synchronized (handler)发现handler锁对象已被Main进程hold,此时threadb阻塞等待
3.Main继续执行hanlder.wait(),释放handler锁并等待
4.threadb获得handler锁,初始化bhandler,执行hanlder.notify()
5.Main得到通知,重新请求handler锁,但是此时threadb尚未出同步代码区,没有释放handler锁,Main继续等待,threadb继续执行,释放hanlder
6.Main请求hanlder锁成功,继续执行wait后面的操作
threadb先执行:
1.Main执行 Threadb.start()
2.VM切换执行threadb,获得handler锁。
3.VM切换执行Main,发现hanlder锁被threadb hold,阻塞等待
4.VM切换threadb,继续执行notify,直到出同步代码区,释放hanlder锁
5.VM切换执行Main,获得hanlder锁,执行到wait,阻塞等待别的线程notify
6.这个例子中,notify只执行了一次,所以main,再也等不到别的线程叫它吃饭了(notify),只好饿死
主要问题是notify 不能通知到后到来wait线程,所以解决方法就是确保main线程先进入synchronized,可在threadb 执行synchronized之前判断main是否已经进入synchronized