V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
gramyang
V2EX  ›  Java

Android 上使用 wait/notify 的奇怪 bug

  •  
  •   gramyang · 2019-11-27 18:25:30 +08:00 · 4419 次点击
    这是一个创建于 1824 天前的主题,其中的信息可能已经有所发展或是发生改变。
    在主线程连接了 socket,在异步的准备工作做好了解除主线程阻塞。

    主线程阻塞:
    mConnectThread = new ConnectionManagerImpl.ConnectionThread(" Connect thread for " + info);
    mConnectThread.setDaemon(true);
    mConnectThread.start();
    synchronized (mConnectThread) {
    try {
    mConnectThread.wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    子线程初始化成功后解除主线程阻塞:
    在子 Thread 的 run()中
    synchronized (this) {
    this.notifyAll();
    }

    结果 android 主线程直接无限阻塞了。。。。求大佬支招
    17 条回复    2019-11-29 07:33:02 +08:00
    Kamiyu0087
        1
    Kamiyu0087  
       2019-11-27 18:38:22 +08:00
    把 mConnectThread.start(); 放到 synchronized 块里执行
    你这 wait() 的时候有可能 notifyAll() 已经跑过了
    gramyang
        2
    gramyang  
    OP
       2019-11-27 20:29:46 +08:00
    @Kamiyu0087 mConnectThread.start()不在 synchronized 块里面啊
    Aruforce
        3
    Aruforce  
       2019-11-27 20:56:46 +08:00 via Android
    Synchro 里面的代码块 写 thread.currenthread.wait……你这 Java 真差的可以…
    Aruforce
        4
    Aruforce  
       2019-11-27 20:58:39 +08:00 via Android
    #3

    synchronized (mConnectThread) {
    try {
    Thread.currentThread().wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    falsemask
        5
    falsemask  
       2019-11-27 22:21:39 +08:00
    子线程 syn 的 this 是 mConnectThread 对象吗
    falsemask
        6
    falsemask  
       2019-11-27 22:24:02 +08:00
    @Aruforce 你要不要试试你写的代码,你 synchronized 获取了 mConnectThread 的锁,然后在 Thread.currentThread()上 wait,你确定不会抛异常?
    hhx
        7
    hhx  
       2019-11-28 01:07:55 +08:00 via Android
    简单的线程同步,用初值为 0 的信号量即可,Java 中的 Semaphore。你程序的问题我想一楼的回答是正确的,你自己也说了是异步,走走停停不是一贯到底。
    gramyang
        8
    gramyang  
    OP
       2019-11-28 07:31:17 +08:00
    @falsemask 是的
    gramyang
        9
    gramyang  
    OP
       2019-11-28 07:32:08 +08:00
    @falsemask 所以我最烦这种没长眼睛,上来就秀优越感的人,v 站特别多,水平不怎么样还特爱装逼,我都懒得搭理
    gramyang
        10
    gramyang  
    OP
       2019-11-28 07:41:48 +08:00
    @Kamiyu0087
    @hhx
    我测试了一下,不行。果然还是我猜测的那样,android 里面的主线程是不能阻塞的,只要手动 wait 就会卡死。。。必须放到子线程里面去才行
    Aruforce
        11
    Aruforce  
       2019-11-28 08:09:35 +08:00 via Android
    @falsemask 抛什么异常? Illegal monitor ?别逗…
    GuuJiang
        12
    GuuJiang  
       2019-11-28 09:49:17 +08:00
    这是一个对 monitor 对象及 wait/notify/notifyAll 等方法的典型误解,要注意这几个方法是定义在 Object 类里的,从逻辑上来说 monitor 对象表示的是你需要控制互斥及同步访问的资源本身,而不是线程,这就是为什么很多代码里会有类似 Object lock = new Object()这样的语句,作为 monitor 的对象只需要跟你想要控制的资源有个一一对应的关系即可,基本不会有把 Thread 对象作为 monitor 的需求

    jdk 源码的 Thread.join 方法的注释里有这样一句话

    It is recommended that applications not use wait, notify, or notifyAll on Thread instances.
    gramyang
        13
    gramyang  
    OP
       2019-11-28 10:37:13 +08:00
    @GuuJiang 关键是我现在的需求就是保证一个线程阻塞直至另一个线程执行完后再执行,而 android 的主线程不允许有任何阻塞的操作,至于是用 object 的 wait 还是 condition 的 wait 还是 future 的 get 没有区别。
    BrokenVns
        14
    BrokenVns  
       2019-11-28 12:40:57 +08:00
    1.主线程是可以有阻塞操作的,但不建议。
    2.我觉得你的 synchronized (mConnectThread)和 synchronized (this)可能不是同一对象,你这个 this 是 Thread 还是 Runnable ?我建议你把这两个对象打印出来看一下。
    3.你可以试试定义额外的对象作为锁来试试,比如都使用 synchronized (lockObject)
    gramyang
        15
    gramyang  
    OP
       2019-11-28 17:53:57 +08:00
    @BrokenVns mConnectThread 和 this 是同一个对象,this 是 Thread 的子类。synchronized (object)和 synchronized (this)应该是一样的吧?前提是 object 和 this 都是只有一个
    BrokenVns
        16
    BrokenVns  
       2019-11-28 19:34:11 +08:00
    @gramyang 你的 run()是在 ConnectThread 类里直接重写的吗?
    我见过有人这么写的:
    t = new Thread(()->{
    synchronized (this){...}
    });
    synchronized (t){...}
    上面这种情况就把对象混淆了。
    如果不是我猜的这种情况,你多加点 log 看看,要不试试第 3 条。
    gramyang
        17
    gramyang  
    OP
       2019-11-29 07:33:02 +08:00
    @BrokenVns 不是这样的,是在 ConnectThread 里面调用的 this
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1566 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 16:50 · PVG 00:50 · LAX 08:50 · JFK 11:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.