gramyang
V2EX  ›  Java

Android 上使用 wait/notify 的奇怪 bug

  •  
  •   gramyang · Nov 27, 2019 · 5795 views
    This topic created in 2533 days ago, the information mentioned may be changed or developed.
    在主线程连接了 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 replies  •  2019-11-29 07:33:02 +08:00
    Kamiyu0087
    Kamiyu0087
    Nov 27, 2019
    1
    把 mConnectThread.start(); 放到 synchronized 块里执行
    你这 wait() 的时候有可能 notifyAll() 已经跑过了
    gramyang
    gramyang
    OP
    Nov 27, 2019
    2
    @Kamiyu0087 mConnectThread.start()不在 synchronized 块里面啊
    Aruforce
    Aruforce
    Nov 27, 2019 via Android
    3
    Synchro 里面的代码块 写 thread.currenthread.wait……你这 Java 真差的可以…
    Aruforce
    Aruforce
    Nov 27, 2019 via Android
    4
    #3

    synchronized (mConnectThread) {
    try {
    Thread.currentThread().wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    falsemask
    falsemask
    Nov 27, 2019
    5
    子线程 syn 的 this 是 mConnectThread 对象吗
    falsemask
    falsemask
    Nov 27, 2019
    6
    @Aruforce 你要不要试试你写的代码,你 synchronized 获取了 mConnectThread 的锁,然后在 Thread.currentThread()上 wait,你确定不会抛异常?
    hhx
    hhx
    Nov 28, 2019 via Android
    7
    简单的线程同步,用初值为 0 的信号量即可,Java 中的 Semaphore。你程序的问题我想一楼的回答是正确的,你自己也说了是异步,走走停停不是一贯到底。
    gramyang
    gramyang
    OP
    Nov 28, 2019
    8
    @falsemask 是的
    gramyang
    gramyang
    OP
    Nov 28, 2019
    9
    @falsemask 所以我最烦这种没长眼睛,上来就秀优越感的人,v 站特别多,水平不怎么样还特爱装逼,我都懒得搭理
    gramyang
    gramyang
    OP
    Nov 28, 2019
    10
    @Kamiyu0087
    @hhx
    我测试了一下,不行。果然还是我猜测的那样,android 里面的主线程是不能阻塞的,只要手动 wait 就会卡死。。。必须放到子线程里面去才行
    Aruforce
    Aruforce
    Nov 28, 2019 via Android
    11
    @falsemask 抛什么异常? Illegal monitor ?别逗…
    GuuJiang
    GuuJiang
    Nov 28, 2019
    12
    这是一个对 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
    gramyang
    OP
    Nov 28, 2019
    13
    @GuuJiang 关键是我现在的需求就是保证一个线程阻塞直至另一个线程执行完后再执行,而 android 的主线程不允许有任何阻塞的操作,至于是用 object 的 wait 还是 condition 的 wait 还是 future 的 get 没有区别。
    BrokenVns
    BrokenVns
    Nov 28, 2019
    14
    1.主线程是可以有阻塞操作的,但不建议。
    2.我觉得你的 synchronized (mConnectThread)和 synchronized (this)可能不是同一对象,你这个 this 是 Thread 还是 Runnable ?我建议你把这两个对象打印出来看一下。
    3.你可以试试定义额外的对象作为锁来试试,比如都使用 synchronized (lockObject)
    gramyang
    gramyang
    OP
    Nov 28, 2019
    15
    @BrokenVns mConnectThread 和 this 是同一个对象,this 是 Thread 的子类。synchronized (object)和 synchronized (this)应该是一样的吧?前提是 object 和 this 都是只有一个
    BrokenVns
    BrokenVns
    Nov 28, 2019
    16
    @gramyang 你的 run()是在 ConnectThread 类里直接重写的吗?
    我见过有人这么写的:
    t = new Thread(()->{
    synchronized (this){...}
    });
    synchronized (t){...}
    上面这种情况就把对象混淆了。
    如果不是我猜的这种情况,你多加点 log 看看,要不试试第 3 条。
    gramyang
    gramyang
    OP
    Nov 29, 2019
    17
    @BrokenVns 不是这样的,是在 ConnectThread 里面调用的 this
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1349 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 43ms · UTC 19:17 · PVG 03:17 · LAX 11:17 · JFK 14:17
    ♥ Do have faith in what you're doing.