为何lock.notify无法唤醒等待线程?蓝牙管理线程阻塞问题
问题原因分析
1. 主线程阻塞导致Handler任务无法执行
你创建的phandler默认关联构造函数所在线程的消息队列,如果BluetoothManager是在主线程初始化的,那phandler的Runnable会在主线程执行。而enableBluetooth中调用lock.wait()时,是在主线程的同步块里执行的——wait()会阻塞当前线程,主线程被卡死之后,消息队列完全无法处理后续的Runnable任务,循环检测代码自然停摆,notify()永远不会被调用。
2. 权限判断逻辑完全颠倒
你在enableBluetooth里的权限判断代码是:
if (ActivityCompat.checkSelfPermission(...) != PackageManager.PERMISSION_GRANTED) { // 执行开启蓝牙和wait的逻辑 }
这意味着只有权限未获取时才会进入同步块执行等待逻辑,但实际需要的是权限通过后才去开启蓝牙,这直接导致权限正常时根本不会触发等待逻辑,逻辑完全错误。
3. 线程模型设计错误
wait/notify机制要求等待方和通知方必须在不同线程运行,否则一旦等待方阻塞线程,通知方就没有执行机会。你的代码里等待方(enableBluetooth的wait)和通知方(Runnable的notify)都在同一个线程(主线程),必然造成死锁。
修复思路(不使用广播的情况下)
- 把
enableBluetooth中的等待逻辑放到子线程执行,避免阻塞主线程,让Handler的Runnable能正常在主线程轮询蓝牙状态。 - 修正权限判断逻辑,改为权限通过时才执行开启蓝牙和等待逻辑。
- 确保
wait和notify的调用分别在不同线程,锁的获取与释放逻辑正确。
示例修正片段:
public void enableBluetooth() { BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { return; } if (!mBluetoothAdapter.isEnabled()) { // 修正权限判断:权限通过才执行后续逻辑 if (ActivityCompat.checkSelfPermission(MyApplication.getContext(), android.Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) { // 子线程执行等待逻辑,避免阻塞主线程 new Thread(() -> { synchronized (lock) { mBluetoothAdapter.enable(); Log.i(TAG, "等待蓝牙开启..."); try { lock.wait(); Log.i(TAG, "蓝牙已开启"); isBluetoothOn = true; // 回到主线程触发回调 handler.post(this::onBluetoothConnected); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } else { isBluetoothOn = true; onBluetoothConnected(); } }
另外注意:BluetoothAdapter.enable()是异步操作,系统开启蓝牙需要时间,你设置的10秒轮询间隔太长,建议改成1秒左右,避免不必要的等待延迟。
内容的提问来源于stack exchange,提问作者Charles Semaan
相关产品推荐
相关产品推荐

