0

I have an a ChoiceBox that lists months values, when the user choose a value, it execute this lambda expression:

private TableView<IncomeFX> tableIncome;
private ChoiceBox<Month> choiceBoxIncomeMonths;

private ChangeListener<Month> setChoiceBoxIncomeMonthsBehaviour(){
    ChangeListener<Month> months = (ObservableValue<? extends Month> observable, Month oldValue, Month newValue) -> {
            incomesData.clear();
            Year selectedYear = choiceBoxIncomeYears.getSelectionModel().getSelectedItem();
            ObservableList<IncomeFX> temp = incomeManager.getIncomesOf(selectedYear, newValue);
            incomesData.addAll(temp);

    };
    return months;
}

and how i add the listener:

choiceBoxIncomeMonths.getSelectionModel().selectedItemProperty().addListener(setChoiceBoxIncomeMonthsBehaviour());

when I click on the choicebox, i get:

Exception in thread "JavaFX Application Thread" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:386)
at java.util.AbstractList$Itr.next(AbstractList.java:355)
at java.util.AbstractCollection.addAll(AbstractCollection.java:343)
at javafx.collections.ModifiableObservableListBase.addAll(ModifiableObservableListBase.java:99)
at lite.money.ui.MainUI.lambda$1(MainUI.java:160)
at lite.money.ui.MainUI$$Lambda$120/1680764266.changed(Unknown Source)

it indicate that the problem is in the line where I call: addAll(temp) how can i solve this ??? thanks

usertest
  • 2,140
  • 4
  • 32
  • 51
  • Please post a [MCVE](http://stackoverflow.com/help/mcve) with focus on **complete**. These bits and pieces don't tell what you're doing behind the scenes. – Roland May 23 '15 at 19:08
  • Does this answer your question? [Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop](https://stackoverflow.com/questions/223918/iterating-through-a-collection-avoiding-concurrentmodificationexception-when-re) – 9ilsdx 9rvj 0lo Jan 24 '22 at 14:57

3 Answers3

0

Since you haven't posted all the code, I'm going to guess you are running code on another thread that is trying to interact with the JavaFX data. When another thread tries to do this, it will throw an exception since only the JavaFX thread should be interacting with the data.

I can't really offer any more advice because I don't have the full codebase of what you are doing to truly say "yes at line X you are having thread Y access location X when it should not be."

Are you adding this on another thread perhaps? You will know the application better than I would since I don't have anymore code to go off of.

Water
  • 3,245
  • 3
  • 28
  • 58
  • i'm sorry but what kind of code you want, i posted the check box listener setting, and the lambda expression that is executed when the choiceBox's value is changed, it goes to the db get the observableList that contains the classes to show in the tableview. the table is already populated with some values, that is why i clear it first then i add new value. and no there is no other thread only the main. – usertest May 23 '15 at 17:42
  • ConcurrentModificationException says that you are concurrently modifying something you should not be. Therefore you either are using multiple threads (possibly without knowing) or there is some other bug going on (which I'm guessing is unlikely). Therefore without more code from your application to see if you are doing multiple threads or not, we can't really advise you any further. – Water May 23 '15 at 17:45
  • Also in case you don't believe me: https://docs.oracle.com/javase/8/docs/api/java/util/ConcurrentModificationException.html – Water May 23 '15 at 17:47
  • no man I believed you, it's just i don't know what other code to add, because there is a lot of UI code, there is the logic, and the db code, all related to the choicebox changed value. – usertest May 23 '15 at 18:04
  • @usertest I have an idea, can you go to the line that is causing the error, and right before it print out all the threads? It might look like this: `Set threadSet = Thread.getAllStackTraces().keySet(); Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]); for (Thread t : threadArray) { if (t.isAlive() && !t.isDaemon()) { System.out.println(t); } }` -- Sorry this looks like crap, but I don't want to post it as an answer since I'm not really answering anything. This way we can see if there's any other threads. JavaFX does make it's own thread. – Water May 23 '15 at 18:06
  • three threads: Thread[JavaFX-Launcher,5,main] Thread[main,5,main] Thread[JavaFX Application Thread,5,main]. i didn't know – usertest May 23 '15 at 18:13
  • Two JavaFX threads? Are you creating an application twice? I'm guessing one of those threads is the offender. Maybe its possible that the two threads are somehow locked onto the same reference, and it causes one of them to write at the same time as the other... causing the error? This is worth investigating. – Water May 23 '15 at 18:15
  • ook man i will see how to solve this, when i do i will post the answer – usertest May 23 '15 at 18:21
0

here is how i solve it, it's a bad code i know, but i don't know any other solution, i have to clear it twice or the items will be added like if i didn't clear it, if you do have an other solution i will be happy:

private ChangeListener<Month> setChoiceBoxIncomeMonthsBehaviour(){
    ChangeListener<Month> months = (ObservableValue<? extends Month> observable, Month oldValue, Month newValue) -> {
        if (!lastMonthValuesFired) {
            incomesData.clear();
            Year selectedYear = choiceBoxIncomeYears.getSelectionModel().getSelectedItem();
            ObservableList<IncomeFX> temp = incomeManager.getIncomesOf(selectedYear, newValue);
            ObservableList<IncomeFX> temp2 = FXCollections.observableList(new ArrayList<IncomeFX>());

            for (IncomeFX t : temp) {
                temp2.add(t);
            }
            incomesData.clear();
            incomesData.addAll(temp2);
        }
    };
    return months;
}
usertest
  • 2,140
  • 4
  • 32
  • 51
0

I had the same problem and did some research, this is the solution that I found that worked for me:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**
 * Java Program to demonstrate how to deal with
 * ConcurrentModificationException.
 * Unlike the name suggests, this error can come even if only 
 * one thread is modifying the collection e.g. List. 
 * It happens when you modify collection 
 * while iterating over it e.g. adding new element or removing elements.
 * 
 * If you want to remove elements while traversing list then 
 * make sure you use Iterator's remove() method or not ArrayList's remove()
 * method() to avoid ConcurrentModificationExcetpion.
 * 
 * @author WINDOWS 8
 *
 */
public class ConcurrentModExceptionDemo{

    public static void main(String args[]) {

        List<String> listOfPhones = new ArrayList<String>(Arrays.asList(
                "iPhone 6S", "iPhone 6", "iPhone 5", "Samsung Galaxy 4",
                 "Lumia Nokia"));
        
        System.out.println("list of phones: " + listOfPhones);
        
        // Iterating and removing objects from list
        // This is wrong way, will throw ConcurrentModificationException
        for(String phone : listOfPhones){
            if(phone.startsWith("iPhone")){
               // listOfPhones.remove(phone); // will throw exception
            }
        }
        
        // The Right way, iterating elements using Iterator's remove() method
        
        for(Iterator<String> itr = listOfPhones.iterator();
                                   itr.hasNext();){            
            String phone = itr.next();            
            if(phone.startsWith("iPhone")){
                // listOfPhones.remove(phone);  // wrong again
                itr.remove(); // right call
            }
        }
        
        System.out.println("list after removal: " + listOfPhones);

    }

}

Source

GoingAround
  • 67
  • 1
  • 8