我有两个本地线程池,一个池有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 )
由于
答案 0 :(得分:0)
(您的示例不清楚,但我认为您要求的方案是,一个池中的线程不关心另一个池中的哪个线程获取消息。)
可能有很多方法可以做到这一点,但一个简单的方法是:
消息代理也可以工作,但它可能过度杀死。你很可能不想要一个成熟的消息代理的可靠性/持久性/分发。
答案 1 :(得分:0)
如何让第一个池中的线程与第一个池进行通信 来自第二个池的线程?
我不确定您是否有任何其他特定需求,但如果两个池都是本地的,并且您只是愿意实现一个典型的生产者 - 消费者模式,其中N-Threads(作为池的一部分)充当生产者而另一个M-Threads(作为另一个池的一部分)充当消费者,你不关心第二个池的哪个线程实例处理消息,我会通过 - BlockingQueue
实现。
您采用BlockingQueue
的实例(例如ArrayBlockingQueue
或LinkedBlockingQueue
或PriorityBlockingQueue
并且包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()
。
您创建池实例,线程实例 - 为生产者和使用者分开(向所有线程提供单个队列实例,使其充当通信通道),然后使用池执行这些线程实例。
希望它有所帮助!!
答案 2 :(得分:0)
其他人指出的最直接的方法是在池之间有一个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