简体   繁体   English

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

[英]communication between threads in the different pools java

I have two local threadpools, one pool has 4 threads, second pool has 5 threads. 我有两个本地线程池,一个池有4个线程,第二个池有5个线程。

I want these two pools communicate with each other. 我希望这两个池彼此通信。

For example, first pool's second thread (1.2) communicates with the second pool`s fifth thread (2.5), ie 例如,第一个池的第二个线程(1.2)与第二个池的第五个线程(2.5)通信,即

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

1.2 finished sending the message to 2.5 and wants to send the other message to the second pool, but 2.5 is still busy, but 2.4 if free to process messages from 1.2 1.2已完成将消息发送到2.5,并希望将另一条消息发送到第二个池,但是2.5仍然很忙,但是2.4忙于处理1.2中的消息

How do I make threads from first pool communicate to the first free thread from second pool? 如何使第一个池中的线程与第二个池中的第一个空闲线程通信?

How can I implement it in java? 如何在Java中实现它?

Perhaps I should use a message brokers or something like that? 也许我应该使用消息代理或类似的东西? (or BlockingQueue,Exchanger/Pipereader ) (或BlockingQueue,Exchanger / Pipereader

Thanks 谢谢

(Your example is not clear, but I think you are asking for a scheme where the thread in one pool doesn't care which of the threads in the other pool gets the messages.) (您的示例尚不清楚,但我认为您正在要求一种方案,其中一个池中的线程不关心另一个池中的哪个线程获取消息。)

There are probably many ways to do this, but a simple way is: 可能有很多方法可以做到这一点,但是一个简单的方法是:

  1. create a bounded message queue for each pool 为每个池创建一个有界消息队列
  2. each thread in each pool reads messages from its pool's queue 每个池中的每个线程从其池的队列中读取消息
  3. a thread in one pool sends a message to the other pool by adding the message to the other pool's queue. 一个池中的线程通过将消息添加到另一个池的队列中来将消息发送到另一个池。

A message broker could also work, but it is probably over-kill. 消息代理也可以工作,但可能会过大。 You most likely don't want the reliability / persistence / distribution of a full-blown message broker. 您很可能不想要成熟的消息代理的可靠性/持久性/分发。

How do I make threads from first pool communicate to the first free thread from second pool? 如何使第一个池中的线程与第二个池中的第一个空闲线程通信?

I am not sure if you have any other specific needs but if both pools are local and you are simply willing to implement a typical producer - consumer pattern where N-Threads ( as part of a pool ) are acting as producer and another M-Threads ( as part of another pool ) are acting as consumer and you don't care which threads instance of second pool processes a message, I would go by a - BlockingQueue implementation. 我不确定您是否还有其他特定需求,但是如果两个池都是本地的,并且您只是愿意实现典型的生产者-消费者模式,其中N线程(作为池的一部分)充当生产者,另一个M线程(作为另一个池的一部分)充当使用者,并且您不在乎第二个池的哪个线程实例处理一条消息,我将采用BlockingQueue实现。

You take an instance of BlockingQueue (like ArrayBlockingQueue OR LinkedBlockingQueue OR PriorityBlockingQueue and there are few more implementations in package java.util.concurrent ) and share this instance among actual pool threads while restricting that - take() can be done by only consumer threads and by any consumer thread. 您采用BlockingQueue一个实例(例如ArrayBlockingQueueLinkedBlockingQueuePriorityBlockingQueue并且包java.util.concurrent中包含更多实现),并在实际的池线程之间共享该实例,同时限制take()只能由使用者线程和通过任何使用者线程。

How can I implement it in java? 如何在Java中实现它?

You create your pools like below , 您可以如下创建池,

ExecutorService pool_1 = Executors.newFixedThreadPool(4);

ExecutorService pool_2 = Executors.newFixedThreadPool(4);

Then you give actual threads to these pools which are sharing a blocking queue. 然后,将实际线程分配给共享阻塞队列的这些池。 Threads can be created like below - its just a pseudo code. 可以像下面这样创建线程-它只是一个伪代码。

public class Pool1Runnable implements Runnable {

   private final BlockingQueue queue;

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

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

}

Now you write thread implementations for pool2 and make sure that their run() implementation uses take() on queue. 现在,您为pool2编写线程实现,并确保其run()实现在队列上使用take()

You create pool instances, thread instances - separate for producers and consumers (provide a single queue instance to all threads so it acts as a communication channel ) and then you execute these thread instances with pools. 创建池实例和线程实例-为生产者和使用者分离(为所有线程提供一个队列实例,使其充当通信通道),然后对池执行这些线程实例。

Hope it helps !! 希望能帮助到你 !!

Most straightforward way as indicated by others is to have a BlockingQueue in between the pools. 其他人指出的最直接的方法是在池之间具有BlockingQueue If I'm not mistaken your problem is same as having multiple producers and multiple consumers sending and processing messages respectively. 如果我没记错的话,您的问题就和让多个生产者和多个消费者分别发送和处理消息一样。

Here is one implementation which you can build on. 这是可以建立的一种实现。 There are few parameters for which comments have been added, you can tweak them based on your problem scenario. 几乎没有添加注释的参数,您可以根据自己的问题场景进行调整。 Basically, you have 2 pools and one more pool to invoke the producer and consumer in parallel. 基本上,您有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);
}

} }

Here is the output: 这是输出:

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