我有一个接收对象的回调。我制作了这个对象的副本,我必须将它传递给另一个线程以进行进一步处理。回调尽可能快地返回非常重要。理想情况下,回调会将副本写入某种无锁容器。
我只有从单个线程和一个处理线程调用的回调。
我只需要将一堆双打传递给另一个线程,并且我知道双打的最大数量(大约 40 个)。
有任何想法吗?我对Java不是很熟悉,所以我不知道在线程之间传递东西的常用方法。
我有一个接收对象的回调。我制作了这个对象的副本,我必须将它传递给另一个线程以进行进一步处理。回调尽可能快地返回非常重要。理想情况下,回调会将副本写入某种无锁容器。
我只有从单个线程和一个处理线程调用的回调。
我只需要将一堆双打传递给另一个线程,并且我知道双打的最大数量(大约 40 个)。
有任何想法吗?我对Java不是很熟悉,所以我不知道在线程之间传递东西的常用方法。
如果这只是一次性的事情——你得到了 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()。
最后要考虑的一件事是——你想要一个工作线程来处理回调中的双打,还是想要几个?当需要一次完成一个工作时,拥有一个线程是有意义的——例如,如果您将数组写入文件,那么让多个线程执行此操作通常是没有意义的。如果在每个数组上完成的工作是独立的,那么它是拥有多个工作线程的好选择。
关于如何“在线程之间传递东西”,请记住 Java 中线程最重要的部分是目标,即实现java.lang.Runnable
. 如果你在Thread
没有传入Runnable
实例的情况下构造一个对象,那么目标就是Thread
对象本身(因为java.lang.Thread
implements 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();
}
}
创建一个用双精度数组构造的Runnable实现,然后将其传递给线程池 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));
}
您将创建一个新线程,还是需要访问另一个已经存在的线程?
在第一种情况下,您可以从线程池请求一个新线程,将信息传递给它,告诉它运行,然后返回。
在情况 2 中,您可能需要创建一个可以将数据传递到的中间线程,然后它会保留数据并尝试在(例如)数据处理线程上调用同步函数。如果您不传递给中间线程,那么您不知道在将数据传递给其他同步线程时可能会阻塞多长时间。
从关于线程池的java要点:
http://java.sun.com/docs/books/tutorial/essential/concurrency/pools.html
newCachedThreadPool 方法创建一个带有可扩展线程池的执行器。此执行器适用于启动许多短期任务的应用程序。