将一个简单的java对象从一个线程传递到另一个线程的快速方法

时间:2010-05-27 21:31:45

标签: java performance multithreading nonblocking

我有一个接收对象的回调。我复制了这个对象,我必须将它传递给另一个线程进行进一步处理。回调尽可能快地返回非常重要。理想情况下,回调会将副本写入某种无锁容器。

我只有从单个线程和一个处理线程调用的回调。

我只需要将一堆双打传递给另一个线程,我知道双打的最大数量(大约40)。

有什么想法吗?我对Java不太熟悉,所以我不知道在线程之间传递东西的常用方法。

4 个答案:

答案 0 :(得分:6)

如果这只是一次性的事情 - 你得到40左右的双打,并且想要开始新的线程处理,那么你可以这样做:

public void callback(final double[] myDoubles)
{
  new Thread(){
   public void run() {
      // you can use myDoubles here. it will run on a separate thread.
   }}.start()   
};

如果这是经常发生的事情,那么您需要查看thread pools并使用java.utils.concurrent.BlockingQueue。尽管名称如此,但队列只有在满员时才会阻止。

您可以创建一个双精度数组,其大小与回调方法放入队列的大小相同。 put()操作非常快,因此您的回调方法不会延迟很长时间。 (除非队列已满。)

当对象可用时,您的其他线程将使用队列上的take()方法获取对象。 take()方法阻塞,直到一个对象可用 - 如果你不想这样,但更喜欢保持线程运行,做其他事情,然后使用poll()代替。

最后要考虑的是 - 你是否只想要一个工作线程处理回调中的双打,或者你想要几个?当需要一次完成一项工作时,有一个线程是有意义的 - 例如如果将数组写入文件,通常没有多个线程执行此操作。如果在每个数组上完成的工作是独立的,那么它就是拥有多个工作线程的好选择。

答案 1 :(得分:3)

关于如何“在线程之间传递东西”,请记住,Java中线程最重要的部分是 target ,它是实现java.lang.Runnable的类的实例。如果构造Thread对象而不传入Runnable实例,则目标是Thread对象本身(因为java.lang.Thread实现java.lang.Runnable)。否则,您可能会创建一个实现Runnable的自定义类,构造此类的实例,并将其传递给新构造的Thread实例。在这种情况下,自定义类的实例是目标。

确保线程(基本上是Runnable对象)可以访问对象,这相当于确保Runnable对象具有对象作为实例变量的引用,使对象可访问正在线程中执行的run方法。

以下是如何将double数组的副本传递给新创建的线程的示例:

class MyRunner implements Runnable
{
    double[] m_data;

    public MyRunner(double[] data)
    {
        this.m_data = data;
    }

    public void run()
    {
        // this code is executed in a thread. It can access `m_data`.
    }
}

public class Callback
{
    public void doCallback(double[] data)
    {
        double[] dataCopy = null;
        if (data != null) {
            dataCopy = new double[data.length];
            System.arraycopy(data, 0, dataCopy, 0, data.length);
        }
        MyRunner target = new MyRunner(dataCopy);
        Thread worker = new Thread(target);
        worker.start();
    }
}

答案 2 :(得分:1)

创建Runnable的实现,该实现由双精度数组构成,然后将其传递给thread pool executor

像这样:

public class MyDoublesProcessor implements Runnable {
    double[] doublesArray;
    public MyDoublesProcessor(double[] array) {
        doublesArray = array;
    }

    public void run() {
        //do stuff with array
    }
}

Executor exec = Executors.newFixedThreadPool(1);

void callback(double[] array) { //or whatever your callback is
    exec.execute(new MyDoublesProcessor(array));
}

答案 3 :(得分:0)

您是要创建新线程,还是需要访问已存在的另一个线程?

在案例1中,您可以从线程池中请求一个新线程,传递信息,告诉它运行,然后返回。

在第2种情况下,您可能需要创建一个可以将数据传递给的中间线程,然后它保留在数据上并尝试在(例如)数据处理线程上调用同步函数。如果您没有传递给中间线程,您不知道在将数据传递到其他同步线程时可能会阻塞多长时间。

来自线程池上的java要点:

http://java.sun.com/docs/books/tutorial/essential/concurrency/pools.html

newCachedThreadPool方法创建一个具有可扩展线程池的执行程序。此执行程序适用于启动许多短期任务的应用程序。