1

I have the following code with an ArrayList that is filled in other Java class that is a Thread (this is always filled, I have checked every time), then I have in the Main class the problematic block while(true) and the issue is that never ends if I comment or delete the line System.out.println(IDS.size());

Although are Threads in charge of complete the information I need, I cant show the results until all of them are finished. This is the reason of while(true) block.

public static ArrayList<String> IDS = new ArrayList<String>();
//this arraylist is filled in other classes correctly (each Thread add a element -> 10 in total)


//here is the problem
while (true) {
    //if I comment the next system.out.println line
    //the loop never ends and never breaks
    System.out.println(IDS.size());
    if(IDS.size()==10) {
        break;
    }
 }

//when the array is filled with the 10 elements, I show all the info
for (int k = 0; k < impresoras.size(); k++) {
    System.out.println(impresoras.get(k).ID);   
}

I don´t know why this is happening, can someone helps? Thanks in advance.

  • 1
    You might want to have a look how threads work but one problem would be that `==10` part. What if size changes from <10 to >10 between two checks or never reaches a size of 10? Your loop would never end. – Thomas Aug 26 '20 at 11:16
  • for the code you posted, adding or removing the print won't change about the loop ever ending or not – Stultuske Aug 26 '20 at 11:17
  • 4
    This smells like a race condition. My educated guess: With the print, the code takes so long that its executed in parallel and you actually have an iteration at the moment where the other thread filled it to exactly `10`, hence the `== 10` triggered. Without the print, the code is running so fast that it either already finished before the other thread filled it to `10` or the other thread was executed too fast so its already above `10`. In either case, it is likely a race condition and your approach is flawed. Never rely on the order of thread execution. – Zabuzard Aug 26 '20 at 11:17
  • 2
    In order to synchronize with other threads, you need some kind of locking mechanism, for example the built-in `synchronized` keyword, a [lock](https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/concurrent/locks/package-summary.html), or some higher-level abstraction built on these. – Hulk Aug 26 '20 at 11:17
  • 1
    Please post a [mcve], otherwise we can only _guess_. – Zabuzard Aug 26 '20 at 11:18
  • 1
    The probable reason why adding the call to `System.out.println()` changes the result is because it locks internally (it synchronizes access to the underlying output stream). – Hulk Aug 26 '20 at 11:19
  • 1
    Also note that a `while (true)` loop without any kind of slow operation or `Thread.sleep` will hit ur CPU hard, your code will consume 100% of your CPU and your computer will start lagging hard. – Zabuzard Aug 26 '20 at 11:19
  • 'Java `while(true)` loop never ends': I agree. That's what they're for. `true` is always true, so the `while` condition is always true, so it never ends. Working as designed. '... without `System.out.println()`: irrelevant. Unclear what you're asking. – user207421 Aug 26 '20 at 11:30
  • For waiting on a list of results created by other threads, see for example: https://stackoverflow.com/questions/19348248/waiting-on-a-list-of-future – Hulk Aug 26 '20 at 11:33
  • Also see https://stackoverflow.com/questions/2715983/concurrent-threads-adding-to-arraylist-at-same-time-what-happens – Hulk Aug 26 '20 at 11:39
  • Please add a sleep or yield in while loop, and allow other threads to make progress. – Jayan Aug 26 '20 at 11:41
  • Thanks for all comments, I will post later an ampliation to the code (I have no access now), but I thinks the Hulk´s comment explain the reason "The probable reason why adding the call to System.out.println() changes the result is because it locks internally (it synchronizes access to the underlying output stream)". In any case, I think as most of you say that I need a syncrhonize tool to wait all my threads end and then show the information. – user7380087 Aug 27 '20 at 10:44

1 Answers1

0

Finally I use the join methods for the Threads to avoid the while true loop. So only I have to call the next method and then do the System.out.println of my items, that will be printed when all Threads ends their work.

public static ArrayList<MyThread> threadList = new ArrayList<MyThread>();

public static void openFileAndCreateThreads(String fileName) {
        String line = null;
        FileReader fileReader = null;
        BufferedReader bufferedReader = null;
        try {
            fileReader = new FileReader(fileName);
            bufferedReader = new BufferedReader(fileReader);

            while ((line = bufferedReader.readLine()) != null) {
                String[] line_parts = line.split(";");

                MyThread t= new MyThread(line_parts[0].trim(), line_parts[1], line_parts[2]);
                
                threadList.add(t);
                t.start();
            }
            for (int j=0;j<threadList.size();j++) {
                try {
                    threadList.get(j).join();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            
            }
            bufferedReader.close();
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();

        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                bufferedReader.close();
            } catch (Exception ex) {
            }
        }
    }