Java 为什么对字符串或其他对象使用wait方法?

Java 为什么对字符串或其他对象使用wait方法?,java,multithreading,wait,Java,Multithreading,Wait,我有以下代码: synchronized void myMethod() { String s="aaa"; try { s.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } 代码引发异常。。。 我见过在线程上使用wait方法的代码,这种方法是自解释的和逻辑的 为什么要在像字符串这样的对象上使用wait方法,而不是在主线程上使用它 它有什么用 有这样的实际实现吗 提前感谢您的示

我有以下代码:

synchronized void myMethod() {
  String s="aaa";
  try {
    s.wait();
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
}
代码引发异常。。。 我见过在线程上使用wait方法的代码,这种方法是自解释的和逻辑的

  • 为什么要在像字符串这样的对象上使用wait方法,而不是在主线程上使用它
  • 它有什么用
  • 有这样的实际实现吗

  • 提前感谢

    您的示例代码将无法工作,因为方法正在调用myMethod的实例上同步,而等待在字符串上调用。这将引起一场灾难。您必须调用wait并通知正在锁定的同一对象。得到通知的线程是等待调用notify的锁的线程

    锁定字符串对象是个坏主意,不要这样做。你不想锁定那些你无法推理谁可以获得它们的东西,因为任何人都可以获得它们。应用程序中其他地方的一些代码可能锁定在相同的字符串值上,您可能会发生奇怪的交互、死锁,因为其他代码正在锁定您,或者让其他代码通知您。在调试某些多线程行为时,是否需要考虑字符串是如何汇集的

    您可以通过定义自己的锁并将其设置为私有来限制谁可以获取您的锁,如下所示:

    private final Object LOCK = new Object();
    
    因此,只有调用控制访问的对象的方法的线程才能获得锁:

    public void myMethod() {
       synchronized(LOCK) {
          ...
       }
    }
    
    这样,您就可以确切地知道什么可以获取锁,而不是应用程序中的每个线程都可以获得锁。任何可以获取该对象引用的对象都可以获取锁,因此请将引用保持私有

    您的示例使用wait而不使用带有条件变量的循环的方式非常可疑。线程可以在未收到通知的情况下退出等待调用。即使通知了线程,调度程序也不会给它任何特殊的优先级。另一个线程可以闯进来做一些事情,可能会影响通知通知等待线程的状态,从通知线程到线程可以重新获取开始等待时放弃的锁的时间。出于这两个原因,需要有一个循环,当线程从等待中醒来时,在该循环中重新测试一个条件

    另外,如果“codes using wait method on threads”(代码在线程上使用等待方法)指的是将线程对象用作锁的代码,则这是避免执行的另一种操作,请参阅:

    此实现使用This.wait调用的循环,该循环以This.isAlive为条件。当线程终止时,调用this.notifyAll方法。建议应用程序不要在线程实例上使用wait、notify或notifyAll

    wait()
    方法在
    Object
    中实现,而
    String
    扩展了Object以便可以使用它。 为什么有人用它?问他。这不是一个编程问题

    我能想到的是:

    他可以在一个类中使用
    “lock1.wait()
    ,在另一个类中使用
    “lock1.notify()
    ,它类似于全局锁对象 因为文字是由 编译器,因此引用同一对象
    但是这是非常糟糕的做法

    在调用wait之前,首先需要对对象进行同步。这就是您从中获取异常的原因

    void test() {
        String s = "AAA";
        synchronized( s ) {
            s.wait();
        }
    }
    

    调用notify时必须执行相同的操作,但在这种情况下,这是一个非常糟糕的主意,因为如果线程进入此方法,它将永远不会返回。尽管将其视为字符串文字,但在同一类中的另一个方法中使用相同的文字可能会成功,但不要指望它。

    这是一个没有影响的同步示例


    首先,您不太可能需要在
    字符串上进行同步,毕竟它是不可变的,因此,您不需要它来异步执行任何操作

    其次,您很可能在错误的对象上进行同步,任何正确编写的程序都不会将
    String
    用作同步锁

    第三也是最后一点,
    s
    是一个局部变量。事实上,它持有完全相同的模式,JCIP特别告诉您,如果您内联它,就不要使用该模式:

    synchronized (new Object()) {
        // ...
    }
    
    这是无效的同步,因为它不能保证
    synchronized
    关键字的目的:序列化访问、锁定和释放语义,该语义要求在任何给定时间只有一个线程执行同步块


    正因为如此,每个线程都会有自己的锁-不好。

    有什么例外?@当你尝试
    wait()时,无论你得到什么,都是可悲的
    而不首先获取监视器。@变量:java.lang.IllegalMonitorState例外情况下,在检查等待条件的循环中使用
    wait
    ,并与
    notify(All)
    结合使用。所有其他用法可能都是错误的。看看@biziclop,你不相信引导性问题,是吗?这可能是,可能有一个很好的,普遍的实际原因。但是确实没有。是的,但我的意思是,例如,如果问题是为什么人们写
    “foo.equals(bar)
    ,而不是
    bar.equals(“foo”)
    ,那么会有一个编程答案。在这种情况下,没有,但你必须先问一个问题:)他可能正在使用
    “lock1”。wait()
    “lock1”。notify()
    它将类似于全局锁变量Shi Dima,我正在准备OCJP 6,并在一次考试中发现了此代码。所以我想知道你是否有答案。如果我认识这个人,我就不会把它贴在这里,对吗?这就是为什么我添加了一些我能想到的东西,看看它,因为它除了锁定之外没有任何作用,所以你不太可能意外地从一个公共方法返回它。哦,这太糟糕了,在内部字符串上同步。:)它起作用了。但永远不要这样做。谁来了