简体   繁体   中英

communication between threads in the different pools java

I have two local threadpools, one pool has 4 threads, second pool has 5 threads.

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.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

How do I make threads from first pool communicate to the first free thread from second pool?

How can I implement it in java?

Perhaps I should use a message brokers or something like that? (or 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.

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.

How can I implement it in 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.

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. 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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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