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

Java 将int迭代器传递给for循环中定义的新Runnable,java,multithreading,concurrency,Java,Multithreading,Concurrency,可能重复: 下面是我当前正在运行的代码。我希望能够将迭代器I传递到新的可运行代码中。我知道我通常需要make变量final才能传递到内部类,但这会破坏迭代器的效果。我知道通常我可以尝试将可运行的内部类变成一个真正的类,但这样我就失去了倒计时的效果 private long generateThreads(int cores){ if (cores <= 0) cores = Runtime.getRuntime().availableProcessors();

可能重复:

下面是我当前正在运行的代码。我希望能够将迭代器I传递到新的可运行代码中。我知道我通常需要make变量final才能传递到内部类,但这会破坏迭代器的效果。我知道通常我可以尝试将可运行的内部类变成一个真正的类,但这样我就失去了倒计时的效果

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;
}

有人知道给每个线程一个迭代器,或者创建一个显示所有外部类成员的类,特别是倒计时锁的方法吗?

如果我理解正确,您希望runnable保留对迭代器的引用,以便它可以观察增量。一种线程安全的方法是使用AtomicInteger:


请注意,这假设您只从可运行程序中读取i-如果您也编写它,则条件i.get的行为如果我理解正确,您希望可运行程序保留对迭代器的引用,以便它可以观察增量。一种线程安全的方法是使用AtomicInteger:


请注意,这假设您仅从可运行程序读取i-如果您也写入i,则条件i.get的行为您可以使用以下技巧:

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();
            }
        }
    });
}
编译的原因是数组引用是最终的,但数组的内容可以更改


我不确定这会有多有用,因为尽管我没有彻底阅读您的代码,但它似乎不是线程安全的-线程的执行顺序是不确定的,所以当Runnable实际执行时,您的迭代值可以是任何值。

您可以使用以下技巧:

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();
            }
        }
    });
}
编译的原因是数组引用是最终的,但数组的内容可以更改

我不确定这会有多有用,因为尽管我没有彻底阅读您的代码,但它似乎不是线程安全的-线程的执行顺序是不确定的,所以当Runnable实际执行时,您的迭代值可以是任何值。

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

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


Guava和lambdaJ很容易使用。

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


番石榴和lambdaJ易于使用。

int i=holder[0]螺纹安全吗?我不确定这样做时是否有可见性保证,即使数组是最终的。@assylias它不是线程安全的,但设计IMHO也不是。这个答案确实回答了这个问题。请参见编辑的Answersis int i=保持架[0]线程安全?我不确定这样做时是否有可见性保证,即使数组是最终的。@assylias它不是线程安全的,但设计IMHO也不是。这个答案确实回答了这个问题。见编辑后的回答-我们都因为太复杂而错过了答案。查看Alex的答案:@Bohemian我不知道-他的答案和我们的答案实现了不同的目标-我不确定OP是否希望看到runnable中的计数器更改,或者只是在runnable创建时获得值…@Bohemian看起来你是对的-是的,谢谢。我也对你投了赞成票,但是我选择了另一个,因为我真的只需要在//do work部分的后面将数字作为偏移量,并且使用int比创建一个全新的对象更好。这两种方法都适用于这种情况,但另一种方法需要更少的内存消耗。非常感谢。again@tophersmith116如果这就是你所需要的,那么另一个答案确实更好。哈哈,我们都错过了答案,因为太复杂了。查看Alex的答案:@Bohemian我不知道-他的答案和我们的答案实现了不同的目标-我不确定OP是否希望看到runnable中的计数器更改,或者只是在runnable创建时获得值…@Bohemian看起来你是对的-是的,谢谢。我也对你投了赞成票,但是我选择了另一个,因为我真的只需要在//do work部分的后面将数字作为偏移量,并且使用int比创建一个全新的对象更好。这两种方法都适用于这种情况,但另一种方法需要更少的内存消耗。非常感谢。again@tophersmith116如果这就是你需要的,那么另一个答案确实更好。哇。。。我做了一个总台。非常感谢你。这是
太好了,我觉得自己很傻。哇。。。我做了一个总台。非常感谢你。这太棒了,我觉得自己很愚蠢。