Быстрый способ передать простой Java-объект из одного потока в другой - PullRequest
2 голосов
/ 28 мая 2010

У меня есть обратный вызов, который получает объект. Я делаю копию этого объекта и должен передать ее другому потоку для дальнейшей обработки. Очень важно, чтобы обратный вызов возвращался как можно быстрее. В идеале, обратный вызов записывает копию в какой-то контейнер без блокировки.

У меня вызывается только обратный вызов из одного потока и одного потока обработки.

Мне нужно только передать пару удвоений в другой поток, и я знаю максимальное количество двойников (около 40).

Есть идеи? Я не очень знаком с Java, поэтому я не знаю обычных способов передачи данных между потоками.

Ответы [ 4 ]

6 голосов
/ 28 мая 2010

Если это всего лишь одноразовая вещь - вы получаете 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()   
};

Если это часто случается, вам нужно просмотреть пулы потоков и использовать java.utils.concurrent.BlockingQueue . Несмотря на имя, очередь будет блокироваться только в том случае, если заполнится.

Вы можете создать массив, удваивающий соответствующий размер, который ваш метод обратного вызова помещает в очередь. Операция put () выполняется очень быстро, поэтому ваш метод обратного вызова не будет задерживаться надолго. (если очередь не заполнена.)

Ваш другой поток будет использовать метод take () в очереди, чтобы получить объект, когда объект доступен. Метод take () блокируется до тех пор, пока объект не станет доступен - если вы этого не хотите, но предпочитаете, чтобы поток работал, занимаясь другими делами, тогда используйте poll ().

И последнее, на что нужно обратить внимание: вы хотите, чтобы только один рабочий поток обрабатывал удвоения из обратного вызова, или вы хотите несколько? Наличие одного потока имеет смысл, когда работа должна выполняться по одному - например, если вы записываете массив в файл, обычно нет смысла делать это несколькими потоками. Но если работа над каждым массивом независима, то это хороший вариант для нескольких рабочих потоков.

3 голосов
/ 28 мая 2010

О том, как "передавать вещи между потоками", следует помнить, что наиболее важной частью потока в 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();
    }
}
1 голос
/ 28 мая 2010

Создайте реализацию Runnable , которая создается с массивом значений типа double, а затем передайте ее в исполнитель пула потоков .

Вот так:

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));
}
0 голосов
/ 28 мая 2010

Будете ли вы создавать новый поток или вам нужен доступ к другому потоку, который уже существует?

В случае 1, вы могли бы просто запросить новый поток из пула потоков, передать ему информацию, сказать ему, чтобы он выполнялся, а затем вернуть.

В случае 2 вам может потребоваться создать промежуточный поток, в который вы можете передавать свои данные, затем он удерживает данные и пытается вызвать синхронизированную функцию (например) в потоке обработки данных. Если вы не переходите к промежуточному потоку, вы не представляете, как долго вы можете заблокировать передачу данных в другой синхронизированный поток.

Из основ Java в пуле потоков:

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

Метод newCachedThreadPool создает исполнителя с расширяемым пулом потоков. Этот исполнитель подходит для приложений, которые запускают много краткосрочных задач.

...