Android线程等待失败求助:页面切换时线程异常或应用卡顿
多页面Socket消息接收线程的等待状态问题
问题场景
在A、B两个页面分别启动了消息接收线程,希望从A切换到B时让A的线程进入等待状态,避免两个线程竞争同一条消息,但实现过程中遇到了问题。
核心代码
接收线程的实现:
// BufferedReader brClient = new BufferedReader(new InputStreamReader(socket.getInputStream())); private class receiveMsg implements Runnable { @Override public void run() { try { String data; while ((data = brClient.readLine()) != null) { // 对应A/B页面的不同消息处理逻辑 } } catch (IOException e) { e.printStackTrace(); } } }
异常情况
在A页面的onPause方法中调用receiveMsgThread.wait()时,抛出如下异常:
java.lang.RuntimeException: Unable to pause activity {com.example.chat/com.example.chat.B_Container_Activity}: java.lang.IllegalMonitorStateException: object not locked by thread before wait()
添加同步块后的卡顿问题
参考方案添加synchronized块后,异常消失,但从A切换到B时应用卡顿,相关日志:
I/System.out: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> onPause I/ZrHungImpl: sendRawEvent. wpId = 257 E/HiView.HiEvent: length is 0 or exceed MAX: 1024 I/om.example.cha: Thread[7,tid=21291,WaitingInMainSignalCatcherLoop,Thread*=0x7b849a5c00,peer=0x16644030,"Signal Catcher"]: reacting to signal 3 I/om.example.cha: I/om.example.cha: Wrote stack traces to tombstoned I/ZrHungImpl: sendRawEvent. wpId = 258 E/HiView.HiEvent: length is 0 or exceed MAX: 1024
解决方案
问题本质
- 调用
wait()必须先持有该对象的锁,否则会抛出IllegalMonitorStateException,这是首次报错的原因。 - 添加同步块后卡顿,是因为在**主线程(
onPause由主线程执行)**中调用wait(),导致主线程被挂起,UI直接失去响应。
正确实现:用开关变量控制线程状态
不要直接调用线程的wait(),改用volatile标志位配合锁来控制线程暂停/恢复,避免主线程阻塞:
修改后的接收线程代码
private BufferedReader brClient; private class receiveMsg implements Runnable { // volatile保证多线程间的状态可见性 private volatile boolean isPaused = false; // 专用锁对象,避免用Thread本身作为锁 private final Object pauseLock = new Object(); // 外部调用此方法暂停线程 public void pauseThread() { isPaused = true; } // 外部调用此方法恢复线程 public void resumeThread() { synchronized (pauseLock) { isPaused = false; pauseLock.notifyAll(); // 唤醒等待中的线程 } } @Override public void run() { try { String data; while ((data = brClient.readLine()) != null) { // 检查是否需要暂停,用while循环防止虚假唤醒 synchronized (pauseLock) { while (isPaused) { pauseLock.wait(); // 此处wait会释放锁,不会阻塞主线程 } } // 执行对应页面的消息处理逻辑 // different operations to fit page A and B } } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
页面生命周期中调用控制方法
在A页面的onPause和onResume中调用线程的控制方法:
private receiveMsg aReceiveThread; @Override protected void onPause() { super.onPause(); if (aReceiveThread != null) { aReceiveThread.pauseThread(); } } @Override protected void onResume() { super.onResume(); if (aReceiveThread != null) { aReceiveThread.resumeThread(); } }
额外优化建议
- 避免多线程共用同一输入流:如果A、B线程共用同一个
brClient,即使暂停A线程,B线程的readLine()依然会读取缓冲区数据,可能导致消息丢失。更合理的方案是只启动一个全局消息接收线程,将消息分发给当前活跃的页面。 - 页面销毁时清理资源:在页面
onDestroy中关闭线程和Socket,避免内存泄漏。
内容的提问来源于stack exchange,提问作者nor1take
相关产品推荐
相关产品推荐

