Tomas Tomas - 16 days ago 9
Java Question

JavaFX. Adding items to the list in different threads is not working

I have 2 class.
First class is controller. When you click on the enter button, in the collection adding many objects in different threads and presented this collection as the class of the controller when the loop exits after 10 iterations.

public class Controller {
private int count = 3;

@FXML
private Button enter;

@FXML
public void getData() throws IOException{
//Create collection
List<String> synchList = Collections.synchronizedList(new ArrayList<String>());

ExecutorService executor = Executors.newFixedThreadPool(count);

for (int i=0; i<10; i++) {

Runnable myThread= new MyThread(synchList);
executor.execute(myThread);

}

executor.shutdown();

System.out.println(synchList); //Show collection
}


The second class is MyThread. It performs some task. The received object is stored in collection early (for example, add 3 of the object with a delay, simulating the performance of some task)

public class MyThread implements Runnable{
public List<String> list = null;

public MyThread(List<String> list){
this.list = list;
}

@Override
public void run() {
try {
Thread.sleep(2000);
list.add("Object2");
Thread.sleep(2000);
list.add("Object3");
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


At the end of the code execution, I get an empty list. Please tell me what am I doing wrong and how to fix this situation? Thank you!

Answer

Take a look at the documentation of ExecutorService.shutdown:

Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation has no additional effect if already shut down.

This method does not wait for previously submitted tasks to complete execution.

Using shutdown only prevents new tasks from being submitted. It does not make sure all tasks are finished.

Instead you could use awaitTermination to achieve the desired effect:

executor.shutdown();

while (true) {
    try {
        if (executor.awaitTermination(1, TimeUnit.HOURS)) {
            break;
        }
    } catch (InterruptedException ex) {
    }
}

System.out.println(synchList); //Show collection

You should however make sure the code isn't run from the application thread, since otherwise the GUI becomes unresponsive...