2016-09-11 17 views
0

假設對象中的字段從null更改爲非null和來回等,具體取決於的操作線程。如果非空則使用值,否則等待並以原子方式獲取它,循環重複

第二個線程應該在發生非空值時才懶惰地採取一些行動。特別是第二個線程應該等到值切換爲非空值。如果它不在等待中,我想確定它的手中有一個非空值。

這看起來並不像隊列情況,因爲第二個線程不會將該元素帶走,只是在恰好可用時才使用它。

它也不適合信號量使用,因爲它再次不會允許.acquire()許可證。

相反,它提醒了內置的等待和比較,但這似乎並不存在。

java.util.concurrent中是否有預定義的設備,我想要識別。如何才能做到這一點?

This是類似的,但沒有一個接受的答案或一個會幫助這裏。

+0

你的方法有一個根本的缺陷 - 你不能保證懶惰的線程會在字段變化之間醒來,所以它可能不會捕獲所有的事件。 – Malt

+0

這不是一個根本的缺陷,而是有意的行爲。這就是爲什麼我寫道:「如果它**發生**獲得一個空值」。如果沒有,這並不重要。 – Harald

+0

多個線程是否會設置值? – erickson

回答

1

以下是依靠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); 
    } 

} 
相關問題