Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - Filling an ArrayList of Threads with loop

this question is probably pretty easy to answer but I just don't get it. I reduced my problem until this little piece of code was left in order to find the "origin" of this problem: I'm trying to fill an ArrayList of Threads with a loop.

public static int u=0;

public void test(){
    while (u <10) {
        synchronized(threadList){
            threadList.add(u, new Thread(){                
                @Override public void run(){                    
                    System.out.println("Thread at Index: " + u);                     
                } 
            });
        }
        u++;            
    }

    threadList.get(2).start();    
}

With the last line I wanted to test the loop above by starting the thread at Index '2'. I'm expecting the console to show "Thread at Index: 2" but instead this is shown: "Thread at Index: 10" No matter which integer I write in the ".get(int)"-method, I receive the index '10'.

Why is that? And how to fix this?

The creation of the threads seems to work...so is the integer 'u' the problem?

I appreciate any kind of help! Thanks in advance!

like image 421
SoundOfTheTuner Avatar asked Aug 23 '13 21:08

SoundOfTheTuner


2 Answers

When you reference u in your run method

@Override public void run(){                    
    System.out.println("Thread at Index: " + u);                     
} 

The current value of u is retrieved. At the end of your loop and when the thread runs, that value is 10.

Try the following

public static int u = 0;

public void test(){
    while (u <10) {
        synchronized(threadList){
            threadList.add(u, new Thread(){     
                int i = u;

                @Override public void run(){                    
                    System.out.println("Thread at Index: " + i);                     
                } 
            });
        }
        u++;            
    }

    threadList.get(2).start();    
}

In your anonymous Thread class, you're setting an instance field i to the value u has when the constructor is called and printing that value when the run() is executed.

You reference u in a context that hasn't been executed yet, a thread. When the run() method eventually gets called, the program will evaluate the variable u, but at that point in the execution of the program, its value will be 10. If, instead, you do the above, the variable i will hold the value at that exact moment. This is because when new Thread gets started and executed, field initialization occurs and u is evaluated right away.

like image 96
Sotirios Delimanolis Avatar answered Oct 18 '22 03:10

Sotirios Delimanolis


    while (u <10) {
        synchronized(threadList){

            final int u_final = u;

            threadList.add(u, new Thread(){                
                @Override public void run(){                    
                    System.out.println("Thread at Index: " + u_final );
                } 
            });
        }
        u++;            
    }

with a final variable, it is clear what its value will be, since it'll never change.

like image 1
ZhongYu Avatar answered Oct 18 '22 03:10

ZhongYu