Semaphore阻塞主线程无法释放求助:获取AccessToken后仍阻塞
主线程阻塞未释放的问题排查
嘿,我来帮你梳理下这个问题——你在MainActivity的onCreate里调用waitUntilAccessTokenIsObtained.acquire()阻塞主线程,异步获取Token后调用release()却没唤醒主线程,大概率是这几个细节没处理到位:
1. 同步工具类的初始化或类型问题
- 如果你用的是
CountDownLatch:初始化时是不是设置了大于1的计数?比如new CountDownLatch(2),那只调用一次countDown()肯定没法唤醒主线程,必须确保计数是1,一次countDown()就能归零。 - 如果你用的是
Semaphore:初始化时是不是给了0个许可?new Semaphore(0),这时候release()是增加许可,acquire()是获取许可,但如果异步请求里的release()没执行到,主线程就会一直阻塞。
2. 异步请求的release()是否真的执行了
- 检查
getAccessToken()的回调逻辑:是不是只在请求成功时才调用release()?如果请求超时、失败或者抛出异常,有没有兜底执行release()?比如只在onSuccess里调用,那请求失败时主线程就永远卡着了。 - 确认异步请求是否在非主线程执行:如果
getAccessToken()实际上是在主线程同步执行的,那acquire()已经把主线程卡死,release()根本没机会运行。
3. 主线程阻塞的生命周期风险
- 在
onCreate里直接阻塞主线程很容易触发ANR(应用无响应),就算后面release()执行了,系统可能已经因为主线程超时把进程杀掉了。建议给acquire()/await()加上超时时间,比如await(5, TimeUnit.SECONDS),避免无限阻塞。
4. 同步工具类的实例是否一致
- 有没有可能
waitUntilAccessTokenIsObtained是多个实例?比如异步请求里调用的是另一个对象的release(),而主线程acquire()的是另一个实例,这种情况下肯定无法触发唤醒,要确保是同一个对象。
正确示例代码(用CountDownLatch)
public class MainActivity extends AppCompatActivity { private CountDownLatch waitForTokenLatch = new CountDownLatch(1); private String currentToken; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 启动异步请求获取Token fetchAccessToken(); try { // 最多等待5秒,防止ANR waitForTokenLatch.await(5, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } // 安全加载资源(如果新Token没拿到就用旧Token) loadAppResources(currentToken != null ? currentToken : getOldToken()); } private void fetchAccessToken() { // 模拟异步网络请求,实际项目可以用Retrofit/OkHttp new Thread(() -> { try { // 模拟网络耗时 Thread.sleep(1500); currentToken = "fresh_access_token_123"; } catch (Exception e) { e.printStackTrace(); // 请求失败,用旧Token兜底 currentToken = getOldToken(); } finally { // 无论成功失败都必须释放,避免主线程阻塞 waitForTokenLatch.countDown(); } }).start(); } private String getOldToken() { // 从SharedPreferences等地方获取旧Token return "old_valid_token_456"; } private void loadAppResources(String token) { // 加载资源的业务逻辑 } }
内容的提问来源于stack exchange,提问作者Ariel Grabijas
相关产品推荐
相关产品推荐

