2014-11-15 98 views
0

我有一個多線程程序,其中一個線程正在讀取數據並且多個其他人正在處理該數據。如果我有一個寫入線程連續添加數據(Example.add())和其他讀取程序線程順序讀取該數據(Example.getData(1),Example.getData(2),...),阻止讀取程序的最佳方式是什麼,直到他們請求的索引處的數據可用?阻塞直到元素可用

這個問題有點像生產者 - 消費者,但我不想「消費」數據。

public class Example { 
    private ArrayList<Integer> data; 

    public Example() { 
    data = new ArrayList<Integer>(); 
    } 

    public int getData(int i) { 
    // I want to block here until the element 
    // index i is available. 

    return data.get(i); 
    } 

    public void add(int n) { 
    data.add(n); 
    } 
} 
+0

這聽起來像你想要麼'Future'(內置於Java,但更多的限制)或'Promise'(較新,反應器規範的一部分)。 – chrylis

回答

1

這似乎是同步線程合理的方式:你可以在這裏找到更多關於它的信息

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html

的條件鏈接顯示了這樣一個例子:

class BoundedBuffer { 
    final Lock lock = new ReentrantLock(); 
    final Condition notFull = lock.newCondition(); 
    final Condition notEmpty = lock.newCondition(); 

    final Object[] items = new Object[100]; 
    int putptr, takeptr, count; 

    public void put(Object x) throws InterruptedException { 
     lock.lock(); 
     try { 
      while (count == items.length) 
       notFull.await(); 
      items[putptr] = x; 
      if (++putptr == items.length) putptr = 0; 
      ++count; 
      notEmpty.signal(); 
     } finally { 
      lock.unlock(); 
     } 
    } 

    public Object take() throws InterruptedException { 
     lock.lock(); 
     try { 
      while (count == 0) 
       notEmpty.await(); 
      Object x = items[takeptr]; 
      if (++takeptr == items.length) takeptr = 0; 
       --count; 
      notFull.signal(); 
      return x; 
     } finally { 
      lock.unlock(); 
     } 
    } 
} 

請不要評論我的代碼風格,這是條件示例中的直接副本。

在你的情況下,你可能會考慮使用所有線程等待的單個鎖,這表示添加新元素時發出信號。這將導致所有線程喚醒並測試它們的元素是否存在。如果不是,他們會回頭等待下一個信號。

如果你想要他們專門等待1元素,你可以保持每個元素的信號,但似乎矯枉過正。

類似:

public class Example { 
    private Lock lock = new ReentrantLock(); 
    private Condition update = lock.newCondition(); 
    public Example(data) { 
     data = new ArrayList<Integer>(); 
    } 

    public int getData(int i) { 
     lock.lock(); 
     try { 
      while (data.get(i) == null) { 
       update.await(); 
      } 
      return data.get(i); 
     } finally { 
      lock.unlock(); 
     } 
    } 

    public void add(int n) { 
     data.add(n); 
     update.signal(); 
    } 
} 
+0

你可以進入關於_Basically_的更多細節嗎? –

+0

當然..感覺條件鏈接中的例子涵蓋了他的大部分用例。並且是懶惰的:D也是代碼以上是我編碼有點醉了所以誰知道它是否工作。我認爲它確實需要測試。 作爲OP使用這種確切形式,我留下的「示例(數據)」。這可能是錯誤的,但不想糾正他的例子 – Joeblade

+0

我很喜歡這種方法,@Joeblade。我試了一下,並對代碼示例進行了一些更新,以防有人需要做類似的事情。 –