Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can this loop ever exit?

So, I ran a test and the results make no sense to me. Lets consider the following code:

ThreadStuffCounter counter_1 = new ThreadStuffCounter(1);
while(counter_1.doProceed) {
    Thread.sleep(500);
    Thread thread = new Thread(counter_1);
    thread.start();
}

With the Runnable as follows:

package test;

public class ThreadStuffCounter implements Runnable {
    public volatile boolean doProceed = true;
    private int id = -1;
    public volatile int i = -1;
    public ThreadStuffCounter(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        for (i = 0; i < 10; i++) {
            System.out.println("i = " + i + " in runnable id = " + id);
            try {
                Thread.sleep(1000);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        doProceed = false;
    }
}

Only one instance of counter is shared between threads. It takes less time for another thread to start then even one increment to be made on the counter.doProceed should, as I understand never be set to false and the loop should continue indefinitely until I get an out of memory exception and cannot start any more threads.

How is it possible for the loop to exit?

EDIT: Modified code to make sure the answer below is correct.

package test;

public class ThreadStuffCounter implements Runnable{

public volatile boolean doProceed = true;
private int id = -1;
volatile int i = -1;
public ThreadStuffCounter(int id){
    this.id = id;
}

@Override
public void run() {
    i = 0;
    while (i < 10){
        System.out.println("i = " + i + " in runnable id = " + id +
                "; from thead id = " + Thread.currentThread().getId());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        i++;
    }
    ThreadStuff.doProceed = false;
}

}

And

package test;

public class ThreadStuff {

public static volatile boolean doProceed = true;

public static void main (String[] args) throws InterruptedException{
    ThreadStuffCounter counter_1 = new ThreadStuffCounter(1);
    while(doProceed){
        Thread.sleep(500);
        Thread thread = new Thread(counter_1);
        thread.start();
    }
}

}

Also, it appears more then n threads are needed if you are running for i < n. You need however many, so that n threads increment at the same time.

like image 533
user1219387 Avatar asked Aug 06 '14 17:08

user1219387


1 Answers

When at least one of the threads executes the for loop and i value is greater or equal than 10, then doProceed variable will be false (yes, this may happen), and since it's volatile this will stop the execution of the while loop that creates and starts new threads. Then, is up to all the threads to just finish executing the code of the for loop and then finishing their execution. This seems to happen because the time to start a new thread in your environment is slower than the time for a current thread to finish its execution. Also, note that several threads may increase i value, which will accelerate the for loop execution.

Probably if you loop to a higher value (not tested) then this could generate an infinite loop and the application will break when there aren't enough resources to create and start new threads.


After some tests using the limit as 10, 50 and 1000. I noticed that when you have a bigger value, since lots of threads are created, all of them increase the value of i at the same time and i slowly starts to get closer to the limit value set in the for loop. Description of my current environment:

  • OS: Windows 7 Professional 64 bits
  • Processor: Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz (4 CPUs), ~2.5GHz
  • Ram: 8192MB
like image 122
Luiggi Mendoza Avatar answered Oct 05 '22 20:10

Luiggi Mendoza