1

重複の可能性:
forループの最後のカウンター?

以下は私が現在実行しているコードです。イテレータiを新しいRunnable()コードに渡せるようにしたいと思います。私は通常、内部クラスに渡すためにmake変数をfinalにする必要があることを知っていますが、それはイテレーターの効果を台無しにします。通常、Runnable内部クラスを真のクラスにしようと試みることができることは知っていますが(用語が不足しているため)、CountDownLatchesの効果が失われます。

private long generateThreads(int cores){
    if (cores <= 0)
        cores = Runtime.getRuntime().availableProcessors();

    System.out.println("Using " + cores + " threads for processing");

    final ExecutorService exec = Executors.newFixedThreadPool(cores);
    final CountDownLatch ready = new CountDownLatch(cores);
    final CountDownLatch start = new CountDownLatch(1);
    final CountDownLatch done = new CountDownLatch(cores);

    for (int i = 1; i <= cores; i++){
        exec.execute(new Runnable(){

            public void run(){
                ready.countDown();
                try{
                    start.await();
                    //do work
                    }
                } catch (InterruptedException e){
                    Thread.currentThread().interrupt();
                } finally{
                    done.countDown();
                    exec.shutdown();
                }
            }
        });
    }

    long startTime = 0;
    try{
        ready.await();
        startTime = System.nanoTime();
        start.countDown();
        done.await();
    } catch (InterruptedException e){
        e.printStackTrace();
    }
    return System.nanoTime() - startTime;
}

各スレッドにイテレータを与える方法、またはすべての外部クラスメンバー、特にCountDownLatchesを表示するクラスを作成する方法を知っている人はいますか?

4

4 に答える 4

4

iループ内の最後の変数にの値を割り当てるだけです。

for (int i = 1; i <= cores; i++){
    final int iFinal = i;

    exec.execute(new Runnable(){

        public void run(){
            ready.countDown();
            try{
                start.await();
                System.out.println( "i=" + iFinal );
            } catch (InterruptedException e){
                Thread.currentThread().interrupt();
            } finally{
                done.countDown();
                exec.shutdown();
            }
        }
    });
}
于 2013-01-02T20:02:35.723 に答える
2

私が正しく理解している場合は、ランナブルが増分を監視できるように、イテレータへの「参照」を保持する必要があります。スレッドセーフであるそれを行う1つの方法は、AtomicInteger:を使用することです。

final AtomicInteger i = new AtomicInteger(1); 
for (; i.get() <= cores; i.incrementAndGet()){
    exec.execute(new Runnable(){

        public void run(){
            //you can access i here
            int j = i.get();
        }
    });
}

これは、Runnablesからのみ読み取ることを前提としていることに注意してください。これiも書き込むと、条件の動作i.get() <= coresが予期しないものになる可能性があります。

于 2013-01-02T19:58:38.080 に答える
0

このトリックを使用できます:

final int[] holder = new int[1]; // the array is final, not its contents

for (int i = 1; i <= cores; i++){
    holder[0] = i;
    exec.execute(new Runnable(){

        public void run(){
            int i = holder[0]; // compiles
            ready.countDown();
            try{
                start.await();
                //do work
                }
            } catch (InterruptedException e){
                Thread.currentThread().interrupt();
            } finally{
                done.countDown();
                exec.shutdown();
            }
        }
    });
}

これがコンパイルされる理由は、配列参照finalであるが、配列の内容を変更できるためです。

これがどれほど役立つかはわかりません。コードを完全に読んでいないのに、スレッドセーフではないようです。スレッドの実行順序は特定できないため、Runnableが実際に実行されるときの反復値は何でもかまいません。 。

于 2013-01-02T19:59:24.637 に答える
0

この種の質問には反しますが、別の解決策は、Javaの関数型プログラミングライブラリのいくつかを使用することです。私はスレッドを書くのが嫌いです。これらのライブラリを使用すると、高階述語論理で解決しようとしている問題を簡単に書き出すことができ、バックグラウンドで同時実行の最適化を処理できます。

GuavaとlambdaJは簡単に操作できます。

于 2013-01-02T21:55:20.703 に答える