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 returnValueSystem.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返すことができるクラスを作成できます。Stringcall()

また、拡張しないBで実装する必要があります。それは機能しますが、それは実装も同様であるという理由だけです。スレッドプールには独自の内部スレッドがあり、送信するかオブジェクトを送信するだけです。CallableThreadThreadRunnableRunnableCallable

最後に、リスト(または任意のJavaコレクション)を処理するときにループを使用する代わりに、以下を使用for (int iする習慣を身に付ける必要があります。

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

を使用する必要ある場合for (int iは、少なくともsize()リストの0からに移動します。

 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 に答える