2

假设我有 A 类和 B 类。A 类只有一个带有以下代码的 main 方法:

public class A{
    public static void main(String[] args){
        String xput = "";
        ExecutorService pool = Executors.newFixedThreadPool(4);
        for(int i = 1; i < number; i++){
            pool.submit(new B(list.get(i-1)));
            xput = B.returnValue;
            System.out.println(xput);//testing purposes
        }
    }
}

B 类扩展了 Thread,看起来像这样:

public class B extends Thread{

    static String returnValue = "";        

    public B(String x){
        super(x);
    }

    public void run(){
        double x = 20;
        returnValue += "Grand total: " +
            NumberFormat.getCurrencyInstance().format(x) + "\n";
    }
}

但是System.out.println(xput)除了空行之外不打印任何内容。有谁知道为什么?显然,我的类有比这更多的代码,但由于我没有得到任何输出,所以我从一个小案例开始。

4

2 回答 2

4

这段代码受到许多竞争条件的影响,因为它们都在更新相同的static String returnValue. System.out.println(xput)此外,当调用时,线程实际上可能还没有运行。您需要使用该future.get()方法等待每个线程完成,并且您不能在将它们提交到线程池的同一循环中执行此操作。

由于 4 个线程将同时运行,并且它们都在更新同一个static字段,因此您需要围绕该变量提供一些同步。我建议改为使用的Future功能ExecutorService而不是修改静态字段。像下面这样的东西应该可以工作:

List<Future<String>> futures = new ArrayList<Future<String>>();
for(int i = 1; i < number; i++){
    B b = new B(list.get(i - 1));
    // submit the job b add the resulting Future to the list
    futures.add(pool.submit(b));
}
// all of the jobs are submitted now
StringBuilder sb = new StringBuilder();
for (Future<String> future : futures) {
   // now join with each of the jobs in turn and get their return value
   sb.append(future.get());
}
System.out.println(sb.toString());

// you should implement Callable _not_ extend thread
public class B implements Callable<String> {
    public String call(){
        ...
        return "some string";
    }
}

Future功能ExecutorService允许您从线程池处理的每个作业中获取结果。您可以使用可以从该方法submit() Callable返回结果String(或其他对象)的类call()

此外,您B应该实施Callablenot extend Thread。虽然它会起作用,但这只是因为它也能Thread实现Runnable。线程池有自己的内部线程,你只提交RunnableCallable反对它。

最后,在处理列表(或任何 Java 集合)时不要使用for (int i循环,您应该养成使用以下方法的习惯:

 for(String x : list) {
    B b = new B(x);
    ...

如果你必须使用,for (int i那么至少从 0 到size()列表的:

 for(int i = 0; i < list.size(); i++) {

这样,如果您更改列表的大小,您也不必记住更改循环。

于 2012-05-01T14:41:19.477 回答
0

没有打印任何内容,因为您在设置“returnValue”之前正在检查它。拥有'returnValue'静态也意味着所有线程都将写入同一个共享变量。

如果你想为你的线程有一个返回值,让它们实现callable<T>而不是线程,并将它们传递给<T> Future<T> submit(Callable<T> task)方法。调用返回的值以获取您要查找的值get()Future<T>

于 2012-05-01T14:46:51.763 回答