views:

230

answers:

4

I have a callback which receives an object. I make a copy of this object, and I must pass it on to another thread for further processing. It's very important for the callback to return as fast as possible. Ideally, the callback will write the copy to some sort of lock-free container.

I only have the callback called from a single thread and one processing thread.

I only need to pass a bunch of doubles to the other thread, and I know the maximum number of doubles (around 40).

Any ideas? I'm not very familiar with Java, so I don't know the usual ways to pass stuff between threads.

A: 

Will you be creating a new Thread, or do you need to access another thread that already exists?

In case 1, you could just request a new Thread from a threadpool, pass it the information, tell it to run, then return.

In case 2, you might need to create an intermediate thread that you can pass your data to, then it holds onto the data and attempts to call a synchronized function on (for instance) a data processing thread. If you don't pass to an intermediate thread, you have no idea how long you might block on passing data to your other synchronized thread.

From the java essentials on threadpooling:

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

The newCachedThreadPool method creates an executor with an expandable thread pool. This executor is suitable for applications that launch many short-lived tasks.

Zak
For case 2, what if the callback is called again before the intermediate thread manages to pass the object to the third thread? How fast is getting a thread from a threadpool? Does it lock?
Adal
In case 2, you basically still do case 1 (create a new thread, managed by a thread manager) , but then let that thread wait on your processing thread. Answer edited to reflect threadpool information.
Zak
A: 

On how to "pass stuff between threads", keep in mind that the most important part of a thread in Java is the target, an instance of a class that implements java.lang.Runnable. If you construct a Thread object without passing in a Runnable instance, then the target is the Thread object itself (because java.lang.Thread implements java.lang.Runnable). Otherwise, you are likely creating a custom class that implements Runnable, constructing an instance of this class, and passing it to a newly-constructed Thread instance. In this case, the instance of the custom class is the target.

Ensuring that the thread, basically the Runnable object, has access to an object is equivalent to ensuring that the Runnable object has a reference to the object as an instance variable, making the object accessible to the run method that is being executed in the thread.

Here is an example of how to pass a copy of a double array to a newly-created thread:

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();
    }
}
Daniel Trebbien
I wouldn't hand-code this stuff - it's much safer to use the concurrency utils.
mdma
+2  A: 

If this is just a one-off thing - you get the 40- or so doubles, and want to start a new thread processing that, then you can do it like this:

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

If this is something that happens often, then you will need to look into thread pools and use a java.utils.concurrent.BlockingQueue. Despite the name, the queue will only block if it becomes full.

You can create an array of doubles the appropriate size which your callback method puts into the queue. The put() operation is very quick and so your callback method will not be delayed for long. (unless the queue is full.)

Your other thread will use the take() method on the queue to get the object when an object is available. The take() method blocks until an object is available - if you don't want that, but prefer to keep the thread running, doing other things, then use poll() instead.

One final thing to consider is - do you want just one worker thread handling the doubles from the callback, or do you want several? Having one thread makes sense when the work needs to be done one at a time - e.g. if you write the array to a file, there's usually no point having multiple threads doing this. Buf if the work done on each array is independent, then it's a good candidate for having multiple worker threads.

mdma
Not all BlockingQueue implementations are bounded. Put only blocks for bounded implementations. Also, put the code block in an SO code block format.
Tim Bender
I think you're splitting hairs here for a simple intro to passing values between threads. A LinkedBlockingQueue can be optionally "unbounded" by setting the bound size to Integer.MAX_VALUE, but all queues run in a finite amount of space, and are in practice bounded by the amount of memory available. A bounded queue offers more useful semantics than an "unbounded" one, especially in the face of other concurrency bugs: if the worker thread is overworked or deadlocked, an unbounded queue will simply grow and grow. A bounded queue fails predictably, clearly indicating worker thread problems.
mdma
An notice I said that "the queue only blocks when it becomes full". An unbounded queue is never full and thus never blocks.
mdma
A: 

Create an implementation of Runnable that is constructed with the array of doubles and then pass it into a thread pool executor.

Like so:

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));
}
Tim Bender