阻止直到元素可用

时间:2014-11-15 00:56:04

标签: java multithreading

我有一个多线程程序,其中一个线程正在读取数据,而另外一个线程正在处理该数据。如果我有一个写入线程不断添加数据(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);
  }
}

2 个答案:

答案 0 :(得分:1)

您可以在java中使用阻塞队列。当队列为空时,它会阻止队列获取数据,直到消耗完为止。您可以在此处找到有关它的更多信息:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

在线查找Java阻塞队列的一些示例,您可以解决问题

答案 1 :(得分: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();
    }
}