繁体   English   中英

Java不同池中线程之间的通信

[英]communication between threads in the different pools java

我有两个本地线程池,一个池有4个线程,第二个池有5个线程。

我希望这两个池彼此通信。

例如,第一个池的第二个线程(1.2)与第二个池的第五个线程(2.5)通信,即

1.2 -> 2.5
1.1 -> 2.2
1.3 -> 2.1
1.4 -> 2.3

1.2已完成将消息发送到2.5,并希望将另一条消息发送到第二个池,但是2.5仍然很忙,但是2.4忙于处理1.2中的消息

如何使第一个池中的线程与第二个池中的第一个空闲线程通信?

如何在Java中实现它?

也许我应该使用消息代理或类似的东西? (或BlockingQueue,Exchanger / Pipereader

谢谢

(您的示例尚不清楚,但我认为您正在要求一种方案,其中一个池中的线程不关心另一个池中的哪个线程获取消息。)

可能有很多方法可以做到这一点,但是一个简单的方法是:

  1. 为每个池创建一个有界消息队列
  2. 每个池中的每个线程从其池的队列中读取消息
  3. 一个池中的线程通过将消息添加到另一个池的队列中来将消息发送到另一个池。

消息代理也可以工作,但可能会过大。 您很可能不想要成熟的消息代理的可靠性/持久性/分发。

如何使第一个池中的线程与第二个池中的第一个空闲线程通信?

我不确定您是否还有其他特定需求,但是如果两个池都是本地的,并且您只是愿意实现典型的生产者-消费者模式,其中N线程(作为池的一部分)充当生产者,另一个M线程(作为另一个池的一部分)充当使用者,并且您不在乎第二个池的哪个线程实例处理一条消息,我将采用BlockingQueue实现。

您采用BlockingQueue一个实例(例如ArrayBlockingQueueLinkedBlockingQueuePriorityBlockingQueue并且包java.util.concurrent中包含更多实现),并在实际的池线程之间共享该实例,同时限制take()只能由使用者线程和通过任何使用者线程。

如何在Java中实现它?

您可以如下创建池,

ExecutorService pool_1 = Executors.newFixedThreadPool(4);

ExecutorService pool_2 = Executors.newFixedThreadPool(4);

然后,将实际线程分配给共享阻塞队列的这些池。 可以像下面这样创建线程-它只是一个伪代码。

public class Pool1Runnable implements Runnable {

   private final BlockingQueue queue;

   public Pool1Runnable(BlockingQueue queue){
     this.queue=queue;
   }

    @Override
    public void run() {
        System.out.println("Pool1Runnable");
    }

}

现在,您为pool2编写线程实现,并确保其run()实现在队列上使用take()

创建池实例和线程实例-为生产者和使用者分离(为所有线程提供一个队列实例,使其充当通信通道),然后对池执行这些线程实例。

希望能帮助到你 !!

其他人指出的最直接的方法是在池之间具有BlockingQueue 如果我没记错的话,您的问题就和让多个生产者和多个消费者分别发送和处理消息一样。

这是可以建立的一种实现。 几乎没有添加注释的参数,您可以根据自己的问题场景进行调整。 基本上,您有2个池和另一个池来并行调用生产者和使用者。

public class MultiProducerConsumer {

private static final int MAX_PRODUCERS = 4;
private static final int MAX_CONSUMERS = 5;

private ExecutorService producerPool = new ThreadPoolExecutor(2, MAX_PRODUCERS, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
private ExecutorService consumerPool = new ThreadPoolExecutor(2, MAX_CONSUMERS, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());

//ThreadPool for holding the main threads for consumer and producer
private ExecutorService mainPool = new ThreadPoolExecutor(2, 2, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());

/**
 * Indicates the stopping condition for the consumer, without this it has no idea when to stop
 */
private AtomicBoolean readerComplete = new AtomicBoolean(false);

/**
 * This is the queue for passing message from producer to consumer.
 * Keep queue size depending on how slow is your consumer relative to producer, or base it on resource constraints
 */
private BlockingQueue<String> queue = new ArrayBlockingQueue<>(1);

public static void main(String[] args) throws InterruptedException {
    long startTime = System.currentTimeMillis();
    MultiProducerConsumer multiProducerConsumer = new MultiProducerConsumer();
    multiProducerConsumer.process();
    System.out.println("Time taken in seconds - " + (System.currentTimeMillis() - startTime)/1000f);
}

private void process() throws InterruptedException {
    mainPool.execute(this::consume);
    mainPool.execute(this::produce);
    Thread.sleep(10); // allow the pool to get initiated
    mainPool.shutdown();
    mainPool.awaitTermination(5, TimeUnit.SECONDS);
}

private void consume() {
    try {
        while (!readerComplete.get()) { //wait for reader to complete
            consumeAndExecute();
        }
        while (!queue.isEmpty()) { //process any residue tasks
            consumeAndExecute();
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        try {
            consumerPool.shutdown();
            consumerPool.awaitTermination(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

private void consumeAndExecute() throws InterruptedException {
    if (!queue.isEmpty()) {
        String msg = queue.take(); //takes or waits if queue is empty
        consumerPool.execute(() -> {
            System.out.println("c-" + Thread.currentThread().getName() + "-" + msg);
        });
    }
}


private void produce() {
    try {
        for (int i = 0; i < MAX_PRODUCERS; i++) {
            producerPool.execute(() -> {
                try {
                    String random = getRandomNumber() + "";
                    queue.put(random);
                    System.out.println("p-" + Thread.currentThread().getName() + "-" + random);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    } finally {
        try {
            Thread.sleep(10); //allow pool to get initiated
            producerPool.shutdown();
            producerPool.awaitTermination(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        readerComplete.set(true); //mark producer as done, so that consumer can exit
    }
}

private int getRandomNumber() {
    return (int) (Math.random() * 50 + 1);
}

}

这是输出:

p-pool-1-thread-2-43
p-pool-1-thread-2-32
p-pool-1-thread-2-12
c-pool-2-thread-1-43
c-pool-2-thread-1-12
c-pool-2-thread-2-32
p-pool-1-thread-1-3
c-pool-2-thread-1-3
Time taken in seconds - 0.1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM