【问题标题】:Java: Object.wait(long) brokenJava:Object.wait(long) 坏了
【发布时间】:2017-06-15 19:58:35
【问题描述】:

在我看来,Object.wait 的超时版本似乎很少按原样使用。这是因为:

  • 该方法不处理虚假唤醒。
  • 该方法没有表明它是否由于通知或超时而返回。

带有谓词作为参数的C++ version 似乎使它正确。带有签名的Object中对应的Java方法

boolean wait(long timeOutMillis, BooleanSupplier condition)

可以方便地使用如下:

Object obj = ...;
BooleanSupplier condition = ...;
synchronized (obj) {
    if (obj.wait(1000, condition)) {
        // condition is fulfilled
    } else {
        // timeout happened
    }
}

作为一种解决方法,我可以使用以下丑陋的辅助方法:

public static boolean safeWait(Object waitObject, long timeOutMillis, BooleanSupplier condition) throws InterruptedException {
    if (condition.getAsBoolean()) {
        return true;
    }
    long rest = timeOutMillis;
    while (true) {
        long t0 = System.currentTimeMillis();
        waitObject.wait(rest);
        long t1 = System.currentTimeMillis();
        long waited = t1 - t0;
        if (condition.getAsBoolean()) {
            return true;
        }
        rest = rest - waited;
        if (rest <= 0) {
            return false;
        }
    }
}

我最好提出一些问题:

  • 我说得对吗,它坏了?
  • 他们为什么不解决这个问题?
  • 有没有更好的方法来解决这个问题?

【问题讨论】:

  • 很难用,但不坏。这就是为什么您应该很少直接使用这些方法。使用来自java.util.concurrent 的更高级别的构造。
  • 回答您的问题:不需要,可以。
  • 取决于“损坏”是否意味着它没有做你希望它做的事情,或者没有做作者想要做的事情。
  • 它没有坏。它只是有你不喜欢的行为。更改它的问题是它可能会影响向后兼容性。
  • @Gray:他们不应该改变它,而是添加一个带有谓词作为参数的方法并弃用旧的。

标签: java multithreading wait


【解决方案1】:

您的safeWait(...) 原则上看起来不错,但您可以稍微简化一下:

public static boolean safeWait(Object waitObject, long timeOutMillis, BooleanSupplier condition)
    throws InterruptedException 
{
    long now = System.currentTimeMillis();
    long end_time = now + timeOutMillis;

    while (! condition.getAsBoolean()) {
        if (now > end_time) {
            return false;
        }
        waitObject.wait(end_time - now);
        now = System.currentTimeMillis();
    }

    return true;
}

【讨论】:

    【解决方案2】:

    Object.wait() 有一些限制,这就是 Java 引入 Lock 的原因。并且通过使用“trylock()”方法,如果锁已被其他线程获取,您的代码不会阻塞。

    见下文:

        Boolean workDone = false;
        while (!workDone) {
            Lock lock = new ReentrantLock();
            Boolean lockAcquired = false;
            try {
                lockAcquired = lock.tryLock(5, TimeUnit.SECONDS);
            } catch (InterruptedException e) {  // this exception will be thrown if current thread is interrupted while acquiring the lock or has its interrupted status set on entry to "tryLock" method.
                Thread.currentThread().interrupt();  // this thread's interrupt status will be set to "true" (this is needed because the current thread's interrupted status was cleared by InterruptedException)
                System.out.println(Thread.currentThread().isInterrupted());  // true
            }
            if (Thread.currentThread().isInterrupted()) {
                // close resources. finish as quick as possible
            }
            if (lockAcquired) {
                // you have the lock. you can execute the critical section of the code (read/modify mutable shared state)
                lock.unlock();  // remember to release the lock at the end of your critical section.
                workDone = true;
            }
        }
    

    【讨论】:

    • 请编辑它以显示 如何 lock.tryLock(...) 更好。即解释布尔返回。此外,正确的模式是在捕获 InterruptedException 之后调用 Thread.currentThread().interrupt()。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-23
    • 1970-01-01
    • 2019-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多