繁体   English   中英

在java中使用线程进行并行处理

[英]Using thread for parallel processing in java

我需要在我的程序中同时运行几个函数。 这些进程返回记录。 但是,一个的输出是另一个的输入。 在这种情况下,如果在一个时间点,函数A需要一些时间将一些记录输出到函数B,我需要函数B等待,直到函数A提供一些记录作为该过程的输入。 我可以通过使用等待,连接等线程功能来实现这一点。或者是否有任何其他方法来实现相同的功能。

编辑:根据下面提到的建议,如果我使用生产者 - 消费者算法与BlockingQueue,ExecutorService,Future和CountDownLatch,我可以实现我要求的所有功能吗?

在大多数情况下,您不需要使用wait 。您需要做的就是选择一个良好的安全结构来用于线程之间的通信,

在这个特定的情况下,我会建议一个并发的queuue实现,也许是BlockingQueue ,如ArrayBlockingQueue

如上所述,您可以使用阻塞队列与生产者使用者

要么

您可以使用java并发的倒计时锁存来解决您的问题。

CountDownLatch如何工作?

CountDownLatch.java类定义了一个构造函数:

//构造一个用给定计数初始化的CountDownLatch。

public void CountDownLatch(int count) {...}

这个计数本质上就是锁存器应该等待的线程数。 此值只能设置一次,而CountDownLatch不提供其他机制来重置此计数。

与CountDownLatch的第一次交互是主线程,它是等待其他线程的goind。 这个主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。 执行将在await()方法上停止,直到其他线程完成执行。

其他N个线程必须引用latch对象,因为它们需要通知CountDownLatch对象它们已经完成了它们的任务。 此通知通过以下方法完成: CountDownLatch.countDown() ; 每次调用方法都会减少构造函数中设置的初始计数,因此,当所有N个线程都调用此方法时,count会达到零,并允许主线程通过await()方法恢复执行。

下面是一个简单的例子。 在Decrementer之后调用了countDown()3次

CountDownLatch, the waiting Waiter is released from the await() call.
CountDownLatch latch = new CountDownLatch(3);

Waiter      waiter      = new Waiter(latch);
Decrementer decrementer = new Decrementer(latch);

new Thread(waiter)     .start();
new Thread(decrementer).start();

Thread.sleep(4000);

public class Waiter implements Runnable{

    CountDownLatch latch = null;

    public Waiter(CountDownLatch latch) {
        this.latch = latch;
    }

    public void run() {
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Waiter Released");
    }
}

public class Decrementer implements Runnable {

    CountDownLatch latch = null;

    public Decrementer(CountDownLatch latch) {
        this.latch = latch;
    }

    public void run() {

        try {
            Thread.sleep(1000);
            this.latch.countDown();

            Thread.sleep(1000);
            this.latch.countDown();

            Thread.sleep(1000);
            this.latch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在您的情况下,您可以使用callable来创建线程而不是runnable,因为您需要从一个线程获取retrun值并且必须将该值传递给第二个线程。

Java的Fork和Join看起来适合您的问题中指定的用例。

请参阅http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html

看看BlockingQueue类和生产者/消费者模式。

第一个线程是从输入阻塞队列获取工作单元并将其输出放入输出阻塞队列(具有大小限制)。 第二个线程正在使用此输出队列作为输入。 使用此方法,您还可以轻松调整线程数。

确保每个工作单位的工作量不小。

这类似于生产者 - 消费者问题。 您可以使用Java的BlockingQueue

进程A将其结果排入队列,进程B将等待,直到A的输出在队列中准备就绪。 当A的输出可用时,B可以读取并使用它。

这看起来像消费者 - 生产者 - 问题。 根据其他人的建议,您可以使用BlockingQueue 以下是如何使用它的示例:

public static void main(final String[] args) {
    final ExecutorService producer = Executors.newSingleThreadExecutor();
    final ExecutorService consumer = Executors.newSingleThreadExecutor();
    final BlockingQueue<Integer> workpieces = new LinkedBlockingQueue<>();

    producer.submit(new Runnable() {

        @Override
        public void run() {
            final Random rand = new Random();

            for (;;) {
                try {
                    workpieces.put(rand.nextInt());
                    Thread.sleep(1000);
                } catch (final InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }

    });

    consumer.submit(new Runnable() {

        @Override
        public void run() {
            for (;;) {
                try {
                    System.out.println("Got " + workpieces.take());
                } catch (final InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }

    });
}

它在生产者线程中每秒生成一个随机数,由消费者线程打印。

您可以在生产者和消费者线程之间使用BlockingQueue。 如果生成器未满,则生成器将继续将结果添加到队列,并且消费者线程可以同时处理来自队列的待处理消息。

暂无
暂无

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

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