Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 带谓词的生产者-消费者_Java_Multithreading_Concurrency_Producer Consumer - Fatal编程技术网

Java 带谓词的生产者-消费者

Java 带谓词的生产者-消费者,java,multithreading,concurrency,producer-consumer,Java,Multithreading,Concurrency,Producer Consumer,我正在寻找一个支持在谓词上阻塞read()s的java集合。我写了一个简单的版本,但它似乎已经被发明了 例如: interface PredicateConsumerCollection<T> { public void put(T t); @Nullable public T get(Predicate<T> p, long millis) throws InterruptedException; } 接口谓词ConsumerCollection{ 公

我正在寻找一个支持在谓词上阻塞
read()
s的java集合。我写了一个简单的版本,但它似乎已经被发明了

例如:

interface PredicateConsumerCollection<T> {

  public void put(T t);

  @Nullable
  public T get(Predicate<T> p, long millis) throws InterruptedException;
}
接口谓词ConsumerCollection{
公开作废认沽权证(T);
@可空
公共T get(谓词p,长毫秒)抛出InterruptedException;
}
put()。如果合适的
T
已在存储中,则
get()
会立即返回,或阻塞直到合适的值被放入(),或超时。消费者之间存在竞争,但公平性在我的案例中并不重要


有人知道这样一个集合吗?

没有立即类可以解决您的问题,但是ConcurrentHashMap和BlockingQueue的组合可能是一个解决方案

哈希映射定义为:

final ConcurrentHashMap<Predicate, LinkedBlockingQueue<Result>> lookup;
最终ConcurrentHashMap查找;
put需要确保,对于每个谓词,一个队列被添加到映射中,这可以使用
putIfAbsent
以线程安全的方式完成

如果您有一组固定的谓词,只需预先填充列表,然后使用者只需调用
lookup.get(谓词).take()


如果谓词的数量未知/太多,您需要为使用者编写一个wait/notify实现,以防谓词还不在您自己的列表中。

我还需要一些非常类似的东西来测试某个JMS异步消息是否在某个超时内收到。事实证明,通过使用基本的等待/通知,您的问题相对容易实现,如中所述。其思想是使put和query方法同步,并让query方法等待。put方法调用notifyAll来唤醒查询方法中所有等待的线程。然后,查询方法必须检查谓词是否匹配。最棘手的事情是获得正确的超时,因为当谓词不匹配时唤醒,并且由于可能的“虚假唤醒”。我发现这提供了答案

以下是我提出的实施方案:

import java.util.ArrayList;
import java.util.List;

// import net.jcip.annotations.GuardedBy;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;

public class PredicateConsumerCollectionImpl<T> implements
        PredicateConsumerCollection<T> {

    // @GuardedBy("this")
    private List<T> elements = new ArrayList<>();

    @Override
    public synchronized void put(T t) {
        elements.add(t);
        notifyAll();
    }

        @Override
public synchronized T query(Predicate<T> p, long millis)
        throws InterruptedException {
    T match = null;
    long nanosOfOneMilli = 1000000L;
    long endTime = System.nanoTime() + millis * nanosOfOneMilli;
    while ((match = Iterables.find(elements, p, null)) == null) {
        long sleepTime = endTime - System.nanoTime();
        if (sleepTime <= 0) {
            return null;
        }
        wait(sleepTime / nanosOfOneMilli,
                (int) (sleepTime % nanosOfOneMilli));
    }
    return match;
}

    synchronized boolean contains(T t) {
        return elements.contains(t);
    }
}
import java.util.ArrayList;
导入java.util.List;
//导入net.jcip.annotations.GuardedBy;
导入com.google.common.base.Predicate;
导入com.google.common.collect.Iterables;
公共类谓词ConsumerCollectionImpl实现
谓词消费集合{
//@guardeby(“本”)
私有列表元素=新的ArrayList();
@凌驾
公共同步作废认沽权(T){
增加(t);
notifyAll();
}
@凌驾
公共同步T查询(谓词p,长毫秒)
抛出中断异常{
T匹配=null;
长纳米奥芬尼=1000000毫升;
long-endTime=System.nanoTime()+毫微米*毫微米;
while((match=Iterables.find(elements,p,null))==null){
long sleepTime=endTime-System.nanoTime();

if(sleepTime)这只适用于每个谓词描述一组不同的
结果的情况。例如,如果您有两个谓词
xGood suggestion and Thank!但不幸的是,在我的情况下,谓词没有提前知道。谢谢。我的类似,我使用了番石榴
SettableFuture
(承诺)为了避免超时等待检查循环。@tariksbl有趣的是,必须添加该样板文件似乎是在复制某些并发实用程序中已经存在的东西。您是否有通过相同单元测试的相同接口的实现?我不明白SettableFuture如何使代码更容易。put方法不应该当谓词匹配的元素进入时,在它上设置en call?这意味着您需要为当前运行的每个查询维护future和谓词的集合。我无权发布代码,但是的,我的impl维护一个waiter集合,该集合在每个
put()
中遍历。
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import org.junit.Before;
import org.junit.Test;

import com.google.common.base.Predicate;

/**
 * Unit test for the {@link PredicateConsumerCollection} implementation.
 * 
 * <p>
 * The tests act as consumers waiting for the test Producer to put a certain
 * String.
 */
public class PredicateConsumerCollectionTest {

    private static class Producer implements Runnable {

        private PredicateConsumerCollection<String> collection;

        public Producer(PredicateConsumerCollection<String> collection) {
            this.collection = collection;
            collection.put("Initial");
        }

        @Override
        public void run() {
            try {
                int millis = 50;
                collection.put("Hello");
                Thread.sleep(millis);
                collection.put("I");
                Thread.sleep(millis);
                collection.put("am");
                Thread.sleep(millis);
                collection.put("done");
                Thread.sleep(millis);
                collection.put("so");
                Thread.sleep(millis);
                collection.put("goodbye!");
            } catch (InterruptedException e) {
                e.printStackTrace();
                fail("Unexpected InterruptedException");
            }
        }

    }

    private PredicateConsumerCollectionImpl<String> collection;
    private Producer producer;

    @Before
    public void setup() {
        collection = new PredicateConsumerCollectionImpl<>();
        producer = new Producer(collection);
    }

    @Test(timeout = 2000)
    public void wait_for_done() throws InterruptedException {
        assertTrue(collection.contains("Initial"));
        assertFalse(collection.contains("Hello"));

        Thread producerThread = new Thread(producer);
        producerThread.start();

        String result = collection.query(new Predicate<String>() {
            @Override
            public boolean apply(String s) {
                return "done".equals(s);
            }
        }, 1000);
        assertEquals("done", result);
        assertTrue(collection.contains("Hello"));
        assertTrue(collection.contains("done"));

        assertTrue(producerThread.isAlive());
        assertFalse(collection.contains("goodbye!"));

        producerThread.join();

        assertTrue(collection.contains("goodbye!"));
    }

    @Test(timeout = 2000)
    public void wait_for_done_immediately_happens() throws InterruptedException {
        Thread producerThread = new Thread(producer);
        producerThread.start();

        String result = collection.query(new Predicate<String>() {
            @Override
            public boolean apply(String s) {
                return "Initial".equals(s);
            }
        }, 1000);
        assertEquals("Initial", result);
        assertFalse(collection.contains("I"));

        producerThread.join();

        assertTrue(collection.contains("goodbye!"));
    }

    @Test(timeout = 2000)
    public void wait_for_done_never_happens() throws InterruptedException {
        Thread producerThread = new Thread(producer);
        producerThread.start();

        assertTrue(producerThread.isAlive());

        String result = collection.query(new Predicate<String>() {
            @Override
            public boolean apply(String s) {
                return "DONE".equals(s);
            }
        }, 1000);

        assertEquals(null, result);
        assertFalse(producerThread.isAlive());
        assertTrue(collection.contains("goodbye!"));
    }

}