将int迭代器传递到在for循环中定义的新Runnable中



可能重复:
for循环中的最后一个计数器?

下面是我当前正在运行的代码。我希望能够将迭代器I传递到新的Runnable((代码中。我知道我通常需要将变量设为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吗?

只需将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();
            }
        }
    });
}

如果我理解正确,您希望可运行程序保留对迭代器的"引用",以便它可以观察增量。一种线程安全的方法是使用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的行为可能是意外的。

你可以使用这个技巧:

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实际执行时,你的迭代值可能是任何值。

这与您的问题不符,但另一种解决方案是使用Java的一些函数式编程库。我讨厌写线程,这些库可以让你简单地写出你试图用高阶逻辑解决的问题,并在幕后处理并发优化。

Guava和lambdaJ很容易使用。

最新更新