Java 在列表中穿行

Java 在列表中穿行,java,multithreading,Java,Multithreading,我有一个应用程序有点慢。我认为使用线程会更快 >,这是我的计划:我的程序有一个 > X类型的对象列表>强> >每个对象X有一个非常大的整数列表< /强>(为了简单起见,我们考虑整数)。 我有一个静态方法(称为getSubsetOfX),它从X的列表中接收对象X,并返回对象X的整数列表。返回的列表是X中包含的所有整数的子集 对于列表中包含的每个X调用此方法。然后我将返回的列表插入整数列表列表中 这是我在精简版中解释的代码: // Class of object X public class X{

我有一个应用程序有点慢。我认为使用线程会更快

>,这是我的计划:我的程序有一个<强> > X类型的对象列表>强> >每个对象X有一个非常大的整数列表< /强>(为了简单起见,我们考虑整数)。 我有一个静态方法(称为getSubsetOfX),它从X的列表中接收对象X,并返回对象X的整数列表。返回的列表是X中包含的所有整数的子集

对于列表中包含的每个X调用此方法。然后我将返回的列表插入整数列表列表中

这是我在精简版中解释的代码:

// Class of object X
public class X{
    public List<Integer> listX;
    ...
}

// Utility class
public class Util{
    // Return a sub-set of Integer contained in X
    public static List<Integer> getSubsetOfX(X x){...}
}


public class exec{
    public static void main(String args[]){
        // Let's suppose that lx is already filled with data!
        List<X> lx = new ArrayList<X>();

        // List of the subsets of integer
        List<List<Integer>> li = new ArrayList<ArrayList<Integer>>();

        for(X x : lx){
            // I want to turn this step "threadrized"
            li.add(getSubsetOfX(x));
        }
    }
}
//对象X的类
公共X类{
公共列表列表x;
...
}
//实用类
公共类Util{
//返回X中包含的整数的子集
公共静态列表getSubsetOfX(X X){…}
}
公共类执行官{
公共静态void main(字符串参数[]){
//让我们假设lx已经充满了数据!
List lx=new ArrayList();
//整数的子集列表
List li=new ArrayList();
对于(X:lx){
//我想将此步骤“线程化”
li.添加(getSubsetOfX(x));
}
}
}
我不知道列表是否允许并发插入。我也不知道如何在其中应用线程。我读了一些关于线程的文章,但是,由于run()方法不返回任何内容,如何将该方法getSubsetOfX(X X)并行化

你能帮我做这个吗

我不知道列表是否允许并发插入

见:

请注意,此实现不可用 同步的。如果有多个线程 访问ArrayList实例 同时,以及至少一个 线程修改列表 从结构上讲,它必须是同步的 外部。(A)结构修改 是添加或删除的任何操作 一个或多个元素,或显式地 调整支持数组的大小;仅 不允许设置元素的值 结构修改。)这是 通常由 在某个对象上同步 自然地封装了列表。如果没有 如果存在这样的对象,则列表应为 使用 Collections.synchronizedList方法。 这最好在创建时完成,以便 防止意外不同步 访问列表:

List list = Collections.synchronizedList(new ArrayList(...));
但要小心:同步带来了巨大的性能成本。这可能会影响使用多个线程所获得的性能(特别是当计算速度相当快时)
因此,尽可能避免访问那些同步的集合。首选线程本地列表,然后使用AddAll将其与共享列表合并

我不知道列表是否允许并发插入

见:

请注意,此实现不可用 同步的。如果有多个线程 访问ArrayList实例 同时,以及至少一个 线程修改列表 从结构上讲,它必须是同步的 外部。(A)结构修改 是添加或删除的任何操作 一个或多个元素,或显式地 调整支持数组的大小;仅 不允许设置元素的值 结构修改。)这是 通常由 在某个对象上同步 自然地封装了列表。如果没有 如果存在这样的对象,则列表应为 使用 Collections.synchronizedList方法。 这最好在创建时完成,以便 防止意外不同步 访问列表:

List list = Collections.synchronizedList(new ArrayList(...));
但要小心:同步带来了巨大的性能成本。这可能会影响使用多个线程所获得的性能(特别是当计算速度相当快时)

因此,尽可能避免访问那些同步的集合。首选线程本地列表,然后使用AddAll将其与共享列表合并

需要澄清的是,
getSubsetOfX()
是一个需要很长时间的调用,对吗

对于这类任务,我建议您看看Java的
Executor
s。第一步是创建一个在给定的
x
实例上运行
getSubsetOfX(x)
的。大概是这样的:

public class SubsetCallable implements Callable<List<Integer>> {
    X x;
    public SubsetCallable(X x) {
        this.x = x;
    }
    public List<Integer> call() {
        return Util.getSubsetOfX(x);
    }
}
ExecutorService exec = ...;
List<SubsetCallable> callables = new LinkedList<SubsetCallable>();
for (X x : lx) {
    callables.append(new SubsetCallable(x));
}
List<Future<List<Integer>>> futures = exec.invokeAll(lc);
for (Future<List<Integer>> f : futures) {
    li.add(f.get());
}

通过这种方式,您可以将密集的计算委托给其他线程,但您仍然只能访问一个线程中的结果列表,因此您不必担心同步问题。(正如winsharp93所指出的,
ArrayList
,与大多数Java的标准集合一样,是不同步的,因此并发访问不安全。)

需要澄清的是,
getSubsetOfX()
是一个需要很长时间的调用,对吗

对于这类任务,我建议您看看Java的
Executor
s。第一步是创建一个在给定的
x
实例上运行
getSubsetOfX(x)
的。大概是这样的:

public class SubsetCallable implements Callable<List<Integer>> {
    X x;
    public SubsetCallable(X x) {
        this.x = x;
    }
    public List<Integer> call() {
        return Util.getSubsetOfX(x);
    }
}
ExecutorService exec = ...;
List<SubsetCallable> callables = new LinkedList<SubsetCallable>();
for (X x : lx) {
    callables.append(new SubsetCallable(x));
}
List<Future<List<Integer>>> futures = exec.invokeAll(lc);
for (Future<List<Integer>> f : futures) {
    li.add(f.get());
}

通过这种方式,您可以将密集的计算委托给其他线程,但您仍然只能访问一个线程中的结果列表,因此您不必担心同步问题。(正如winsharp93所指出的,
ArrayList
,与大多数Java标准集合一样,是不同步的,因此并发访问不安全。)

Hi@winsharp93。你有什么建议可以帮助我在程序中并行执行这一步骤吗?RegardsWell-这取决于您的getSubsetOfX。然而,在许多情况下,使用David Zaslavsky的例子应该是不错的。你有什么建议可以帮助我在程序中并行执行这一步骤吗?RegardsWell-这取决于您的getSubsetOfX。然而,在许多情况下,使用David Zaslavsky的例子应该是不错的。是的@David,慢速方法是getSubsetOfX(X)。这个exec.invokeAll()是并行运行Callables还是linnear运行Callables?ThanksIt取决于您使用哪个
ExecutorService
实现。