1

Possible Duplicate:
A final counter in a for loop?

Below is the code I'm currently running. I'd like to be able to pass the iterator i into the new Runnable() code. I know I usually need the make variables final in order to pass into an inner class, but that ruins the effect of the iterator. I know normally I could try to make the Runnable inner class a true class (excuse my lack of terminology), but then I'd lose the effects of the 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;
}

Does anyone know of a way to give each thread the iterator, or create a class that shows all of the outer class members, particularly the CountDownLatches?

Community
  • 1
  • 1
tophersmith116
  • 432
  • 1
  • 5
  • 19

4 Answers4

4

Just assign value of i to a final variable inside the loop.

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();
            }
        }
    });
}
Alexander Pogrebnyak
  • 44,836
  • 10
  • 105
  • 121
2

If I understand correctly you want the runnable to keep a "reference" to the iterator so that it can observe the increments. One way to do it which is thread safe is to use an 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();
        }
    });
}

Note that this assumes that you only read i from the Runnables - if you also write it, the behaviour of the condition i.get() <= cores could be unexpected.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • lol - we both missed the answer trying to be too complicated. see Alex's answer :) – Bohemian Jan 02 '13 at 20:05
  • @Bohemian I don't know - his answer and ours achieve different goals - I'm not sure whether the OP wants to see the counter change within the runnable or simply get the value at the time the runnable is created... – assylias Jan 02 '13 at 20:06
  • @Bohemian Looks like you are right! ;-) – assylias Jan 02 '13 at 20:08
  • yes, thank you. I voted you up as well, however I chose the other as I really just need the number as an offset later in the //do work section, and just using an int is nicer than creating a whole new object. both methods work in this case, but the other requires less memory consumption. Thank you again – tophersmith116 Jan 02 '13 at 20:10
  • @tophersmith116 If that's what you need then the other answer is better indeed. – assylias Jan 02 '13 at 20:11
  • In a last ditch attempt at a hat, is [this answer](http://stackoverflow.com/questions/12981230/why-is-the-slave-machine-faster-for-reading-than-master-in-database-replication/14145769#14145769) awesome or what? – Bohemian Jan 03 '13 at 19:29
  • @Bohemian Sorry out of vote for the day! You are way ahead of everybody else anyway! – assylias Jan 03 '13 at 22:53
  • Actually, you could help me get a gold badge by voting for the other guy's accepted answer [here](http://stackoverflow.com/questions/7281469/7285304#7285304) – Bohemian Jan 05 '13 at 00:18
  • @Bohemian Upvoted his and yours. – assylias Jan 05 '13 at 00:26
0

You can use this trick:

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

The reason this compiles is that the array reference is final, but the contents of the array is able to be changed.

I'm not sure how useful this will be, because although I didn't read your code thoroughly, it doesn't seem threadsafe - the order of execution of threads is indeterminable, so your iterated value could be anything when the Runnable actually executes.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • is `int i = holder[0]` thread safe? I am not sure that there is a visibility guarantee when doing that (even if the array is final). – assylias Jan 02 '13 at 20:00
  • @assylias It's not threadsafe, but neither is the design IMHO. This answer does answer the question though. (see edited answer) – Bohemian Jan 02 '13 at 20:03
0

This kind of goes against your question but another solution is to work with some of Java's functional programming libraries. I hate writing threads and these libraries let you simply write out the problem you're attempting to solve with higher-order logic and handles concurrency optimization behind the scenes.

Guava and lambdaJ are easy to work with.

Dan
  • 1,179
  • 2
  • 10
  • 18