ConcurrentModificationException on Thread

Hi guys, Please HELP!

Been trying to solve this issue since last night and still cant find any solution. some of you might have encountered and could share ideas on how to solve this.

   PayrollDataGridProperties payroll = new PayrollDataGridProperties(); //GRID

   generateBtn.addClickListener((Button.ClickEvent event) -> {
            payroll.getContainerDataSource().removeAllItems();
            getUI().getSession().getLockInstance();
            try {
                MyRunnable run = new MyRunnable();
                Thread t = new Thread(run);
                t.start();
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                Logger.getLogger(PayrollByGroupUI.class.getName()).log(Level.SEVERE, null, ex);
            }
            UI.getCurrent().setPollInterval(500);
   });

  void processPayroll(int employeeId){
        Employee e = es.findEmployeeById(employeeId);
        double basicSalary = cps.findMonthlySalary(cps.findSalaryGrade(
                            pcps.findPCP(
                                    e.getPositionClassificationPlanId()).getCompensationPlanID()).getSalaryGrade(), 
                    e.getCompensationPlanStep(), 
                    CommonUtil.convertStringToInteger(sslComboBox.getValue().toString()));
        double taxableSalary = atacs.taxableSalary(basicSalary, e.getDependent())/12;
        double grossAmount = basicSalary + PayrollConstants.PERA;
        double withholding = atacs.monthlyTaxDue(taxableSalary, e.getDependent());
        double rlip = atacs.monthlyGsis(basicSalary);
        double phic = atacs.monthlyPhic(basicSalary);
        double hdmf = atacs.monthlyHdmf(basicSalary);        
        double totalDeduction = els.findTotalLoanByEmployee(employeeId) + withholding + rlip + phic + hdmf;
        double netAmountPay = grossAmount - totalDeduction;
        
        payroll.addRow(basicSalary, 
                0.0, 
                basicSalary, 
                PayrollConstants.PERA, 
                grossAmount, 
                withholding, 
                rlip, 
                phic, 
                hdmf, 
                totalDeduction, 
                netAmountPay, 
                netAmountPay/2, 
                netAmountPay/2);
    }

    class MyRunnable implements Runnable {

        @Override
        public void run() {
            List<Employee> eList = es.findAllByPap(getDataId());
            synchronized(eList){
                for(Employee e : eList){
                    processPayroll(e.getEmployeeId());
                    
                    if(current < dataSize){                                              
                        status.setValue(""+(CommonUtil.roundOffToTwoDecimalPlaces((current/dataSize)*100))+"%");
                        current += 1;
                        progress.setValue(new Float(current/dataSize));
                    } else {
                        status.setValue("Finished... 100%");
                    }
                }  
            }             
        }
        
    }

First attempt to execute the code will cause an error:

java.util.ConcurrentModificationException at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1216) at java.util.ArrayList$SubList.size(ArrayList.java:1025) at java.util.Collections$UnmodifiableCollection.size(Collections.java:1090)... second attempt will cause an error:

Exception in thread "Thread-37" java.lang.IllegalStateException: A connector should not be marked as dirty while a response is being written.
    at com.vaadin.ui.ConnectorTracker.markDirty(ConnectorTracker.java:505)
    at com.vaadin.server.AbstractClientConnector.markAsDirty(AbstractClientConnector.java:141)
    at com.vaadin.server.communication.data.RpcDataProviderExtension.insertRowData(RpcDataProviderExtension.java:450) 

after I try again to execute the code It will run without a problem. I already have a previous project using the same execution but I dont know what causes the error on this one. It will only load about 400+ data to the Grid.

Use
ui.access(runnable)
, when updating UI form another thread:
Server Push
.

I’ve tried your suggestion but all the data was loaded in a Grid at the same time. I want to see the grid updated row by row to verify that all data are being loaded inside the Grid when clicking the button with Threading.

I tried this approach:

generateBtn.addClickListener((Button.ClickEvent event) -> { getUI().getSession().getLockInstance(); try { MyRunnable run = new MyRunnable(); Thread.sleep(1000); UI.getCurrent().access(run); } catch (InterruptedException ex) { Notification.show("Error on Group Payroll Thread!", Notification.Type.ERROR_MESSAGE); Logger.getLogger(PayrollByGroupUI.class.getName()).log(Level.SEVERE, null, ex); } UI.getCurrent().setPollInterval(500); }); and this one:

[code]
generateBtn.addClickListener((Button.ClickEvent event) → {
getUI().getSession().getLockInstance();
new ProcessGroupPayroll().start();
UI.getCurrent().setPollInterval(500);
});

class ProcessGroupPayroll extends Thread {

    @Override
    public void run(){
        try {
            Thread.sleep(1000);                
            UI.getCurrent().access(new Runnable() {
                
                @Override
                public void run() {
                    List<Employee> eList = es.findAllByPap(getDataId());
                    synchronized(eList){
                        for(Employee e : eList){
                            processPayroll(e.getEmployeeId());

                            if(current < dataSize){                                              
                                status.setValue(""+(CommonUtil.roundOffToTwoDecimalPlaces((current/dataSize)*100))+"%");
                                current += 1;
                                progress.setValue(new Float(current/dataSize));
                            } else {
                                status.setValue("Finished... 100%");
                            }
                        }  
                    } 
                    
                }                    
            });
            
            UI.getCurrent().access(new Runnable() {

                @Override
                public void run() {
                    savePayroll.setEnabled(true);
                }
            });
        } catch (InterruptedException ex) {
            Logger.getLogger(PayrollByGroupUI.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
}

[/code]Both solution as provided me the same output…

Try to lock session during adding the row only:

UI.getCurrent().access(() -> {
    payroll.addRow(basicSalary, 
                0.0, 
                basicSalary, 
                PayrollConstants.PERA, 
                grossAmount, 
                withholding, 
                rlip, 
                phic, 
                hdmf, 
                totalDeduction, 
                netAmountPay, 
                netAmountPay/2, 
                netAmountPay/2)

});
[/code]

What do you mean by locking the session during adding the row?

PayrollDataGridProperties payroll = new PayrollDataGridProperties(); //GRID

generateBtn.addClickListener((Button.ClickEvent event) -> {
payroll.getContainerDataSource().removeAllItems();
try {
MyRunnable run = new MyRunnable();
Thread t = new Thread(run);
t.start();
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(PayrollByGroupUI.class.getName()).log(Level.SEVERE, null, ex);
}
UI.getCurrent().setPollInterval(500);
});

void processPayroll(int employeeId){
Employee e = es.findEmployeeById(employeeId);
double basicSalary = cps.findMonthlySalary(cps.findSalaryGrade(
pcps.findPCP(
e.getPositionClassificationPlanId()).getCompensationPlanID()).getSalaryGrade(),
e.getCompensationPlanStep(),
CommonUtil.convertStringToInteger(sslComboBox.getValue().toString()));
double taxableSalary = atacs.taxableSalary(basicSalary, e.getDependent())/12;
double grossAmount = basicSalary + PayrollConstants.PERA;
double withholding = atacs.monthlyTaxDue(taxableSalary, e.getDependent());
double rlip = atacs.monthlyGsis(basicSalary);
double phic = atacs.monthlyPhic(basicSalary);
double hdmf = atacs.monthlyHdmf(basicSalary);
double totalDeduction = els.findTotalLoanByEmployee(employeeId) + withholding + rlip + phic + hdmf;
double netAmountPay = grossAmount - totalDeduction;
UI.getCurrent().access(() -> {
payroll.addRow(basicSalary,
0.0,
basicSalary,
PayrollConstants.PERA,
grossAmount,
withholding,
rlip,
phic,
hdmf,
totalDeduction,
netAmountPay,
netAmountPay/2,
netAmountPay/2);
});
}

class MyRunnable implements Runnable {

@Override
public void run() {
List<Employee> eList = es.findAllByPap(getDataId());
synchronized(eList){
for(Employee e : eList){
processPayroll(e.getEmployeeId());
UI.getCurrent().access(() -> {
if(current < dataSize){
status.setValue(""+(CommonUtil.roundOffToTwoDecimalPlaces((current/dataSize)*100))+"%");
current += 1;
progress.setValue(new Float(current/dataSize));
} else {
status.setValue("Finished... 100%");
}
});
}
}
}

};

It WORKS!

THANK YOU VERY MUCH!!!