我想知道是否有一种简单的方法来制作synchronized锁,以响应不断变化的引用。我有看起来像这样的代码:

private void fus(){
    synchronized(someRef){
        someRef.roh();
    }
}
...
private void dah(){
    someRef = someOtherRef;
}

我想发生的是:
  • 线程A输入fus,并在调用someref时获得对roh()的锁定。假设roh永不终止。
  • 线程B输入fus,开始等待someRef`释放,并停留在那里(目前)。
  • 线程C输入dah并修改someRef
  • 现在允许线程B进入同步块(synchronized block),因为someRef不再引用线程A锁定的对象。

  • 实际发生的是:
  • 线程A输入fus,并在调用someref时获得对roh()的锁定。假设roh永不终止。
  • 线程B输入fus,找到锁,并等待其释放(永远)。
  • 线程C输入dah并修改someRef
  • 线程B继续等待,因为它不再查看someref,而是查看A持有的锁。

    有没有一种方法可以使线程B要么重新检查锁以更改引用,要么将其“弹开”到其他代码中? (类似于sychronizedOrElse吗?)

    最佳答案

    当然有办法,但是synchronized却没有。推理:在第二个线程输入fus()的时间点,第一个线程持有someRef引用的对象的固有锁定。重要提示:第​​二个线程仍会在此对象上看到someRef引用,并将尝试获取此锁。稍后,当第三个线程更改引用someRef时,它将不得不以某种方式通知第二个线程此事件。 synchronized是不可能的。

    据我所知,没有像synchronized这样的内置语言功能来处理这种同步。

    一种稍微不同的方法是在您的类中管理 Lock 或给someRef一个Lock类型的属性。可以使用lock()tryLock()来代替tryLock(long timeout, TimeUnit unit)。这是关于如何实现此方案的方案(假设someRef具有Lock属性):

    volatile SomeRef someRef = ... // important: make this volatile to deny caching
    ...
    private void fus(){
        while (true) {
            SomeRef someRef = this.someRef;
            Lock lock = someRef.lock;
            boolean unlockNecessary = false;
            try {
                if (lock.tryLock(10, TimeUnit.MILLISECONDS)) { // I have chonse this arbritrarily
                    unlockNecessary = true;
                    someRef.roh();
                    return; // Job is done -> return. Remember: finally will still be executed.
                            // Alternatively, break; could be used to exit the loop.
                }
            } catch (InterruptException e) {
                e.printStackTrace();
            } finally {
                if (unlockNecessary) {
                    lock.unlock();
                }
            }
        }
    }
    ...
    private void dah(){
        someRef = someOtherRef;
    }
    

    现在,当someRef更改时,第二个线程将在下一个周期中看到someRef的新值,因此,如果没有其他线程获得Lock,它将尝试在新的Lock上进行同步并成功。

  • 10-04 13:59