Java 如果非null,则使用value,否则等待并原子地获取它,在循环中重复
假设一个对象中的一个字段根据one线程的操作从null变为非null并来回变化,等等 当第二个线程碰巧获得非空值时,它将惰性地执行一些操作。特别是,第二个线程应等待值切换为非空。如果它不在等待中,我想确保它手里有一个非null 这看起来不像是队列情况,因为第二个线程不会带走该元素,它只是在碰巧有一个元素可用时使用它 它也不适合使用信号量,因为它同样不会获得许可证 相反,它让人想起了compare and get with Build in wait,但这似乎并不存在 在Java 如果非null,则使用value,否则等待并原子地获取它,在循环中重复,java,multithreading,Java,Multithreading,假设一个对象中的一个字段根据one线程的操作从null变为非null并来回变化,等等 当第二个线程碰巧获得非空值时,它将惰性地执行一些操作。特别是,第二个线程应等待值切换为非空。如果它不在等待中,我想确保它手里有一个非null 这看起来不像是队列情况,因为第二个线程不会带走该元素,它只是在碰巧有一个元素可用时使用它 它也不适合使用信号量,因为它同样不会获得许可证 相反,它让人想起了compare and get with Build in wait,但这似乎并不存在 在java.util.con
java.util.concurrent
中是否有一个预定义的设备,我无法识别。如何做到这一点
类似,但没有公认的答案或对此有帮助的答案。这是一个依靠
ReentrantLock
管理volatile
字段的实现。这在很大程度上借鉴了双重检查锁定的习惯用法,但是读取操作不是创建值本身,而是等待一个条件来表示已经设置了值
使用接受超时的版本重载了get()
方法。两个版本都是可中断的
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BlockingRef<V> {
private final Lock lock = new ReentrantLock(true);
private final Condition signal = lock.newCondition();
private volatile V value;
public BlockingRef() {
this(null);
}
public BlockingRef(V initialValue) {
this.value = initialValue;
}
public final void set(V value) {
lock.lock();
try {
this.value = value;
signal.signalAll();
} finally {
lock.unlock();
}
}
public final V get() throws InterruptedException {
V result = value;
if (result == null) {
lock.lockInterruptibly();
try {
for (result = value; result == null; result = value)
signal.await();
} finally {
lock.unlock();
}
}
return result;
}
public final V get(long time, TimeUnit unit)
throws TimeoutException, InterruptedException
{
V result = value;
if (result == null) {
long start = System.nanoTime();
if (!lock.tryLock(time, unit)) throw new TimeoutException();
try {
time = unit.toNanos(time);
for (result = value; result == null; result = value) {
long wait = time - (System.nanoTime() - start);
if (wait <= 0) throw new TimeoutException();
signal.await(wait, TimeUnit.NANOSECONDS);
}
} finally {
lock.unlock();
}
}
return result;
}
@Override
public String toString() {
return String.valueOf(value);
}
}
import java.util.concurrent.TimeUnit;
导入java.util.concurrent.TimeoutException;
导入java.util.concurrent.locks.Condition;
导入java.util.concurrent.locks.Lock;
导入java.util.concurrent.locks.ReentrantLock;
公共类封锁REF{
私有最终锁定=新的可重入锁定(true);
私有最终条件信号=lock.newCondition();
私有变量V值;
公共封锁REF(){
这个(空);
}
公共封锁参考(V初始值){
this.value=初始值;
}
公共最终无效集(V值){
lock.lock();
试一试{
这个值=值;
signal.signalAll();
}最后{
lock.unlock();
}
}
public final V get()抛出InterruptedException{
V结果=数值;
如果(结果==null){
lock.lockinterruptbly();
试一试{
for(结果=值;结果=空;结果=值)
信号。等待();
}最后{
lock.unlock();
}
}
返回结果;
}
公共最终V get(长时间,时间单位)
抛出TimeoutException、InterruptedException
{
V结果=数值;
如果(结果==null){
长启动=System.nanoTime();
如果(!lock.tryLock(time,unit))抛出新的TimeoutException();
试一试{
时间=单位为托纳诺斯(时间);
for(结果=值;结果=空;结果=值){
长时间等待=时间-(System.nanoTime()-start);
if(wait)你的方法有一个基本缺陷——你不能保证懒惰线程会在字段更改之间醒来,因此它可能不会捕获所有事件。这不是一个基本缺陷,而是预期的行为。这就是为什么我写:“如果它碰巧得到一个空值”。如果没有,这并不重要。多个线程会设置该值吗?啊,好问题。只有一个线程会随该值更改。