Al ejecutar este código, cambiar cualquier elemento de la segunda columna de la tabla (la que emplea un editor diferente del estándar) y volver a hacer clic en la primera columna se lanza una ConcurrentModificationException. Sin embargo, el código parece emplear sincronización de modo correcto para proteger la lista que lanza la excepción. ¿Cuál es el problema con este código?. Las respuestas en los comentarios, por favor :)
package examen; import java.awt.*; import java.util.*; import java.util.List; import javax.swing.*; import javax.swing.event.CellEditorListener; import javax.swing.table.*; public class ProblemaConcurrencia extends JFrame { public ProblemaConcurrencia() { this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Object[][] datos = { {"Mary", "Esquiar", }, {"Lucas", "Esquiar"}, {"Kathya", "Escalar"}, {"Marcus", "Andrews", "Correr"}, {"Angela", "Nadar"} }; String[] columnNames = {"Nombre", "Pasatiempo"}; DefaultTableModel tableModel = new DefaultTableModel(datos, columnNames); JTable tabla = new JTable(tableModel); tabla.setRowHeight(20); TableColumnModel tablaColumnModel = tabla.getColumnModel(); tablaColumnModel.getColumn(1).setCellEditor((new TableCellEditorJComboboxHobbbies())); JScrollPane scrollPane = new JScrollPane(tabla); tabla.setPreferredScrollableViewportSize(new Dimension(500, 70)); getContentPane().add(scrollPane, BorderLayout.CENTER); } public static void main(String[] args) { Runnable r = new Runnable() { public void run() { ProblemaConcurrencia frame = new ProblemaConcurrencia(); frame.pack(); frame.setVisible(true); } }; SwingUtilities.invokeLater(r); } } class TableCellEditorJComboboxHobbbies extends JComboBox implements TableCellEditor { private static String[] opciones = {"Esquiar", "Patinar", "Correr", "Nadar", "Escalar"}; private final List listeners = new ArrayList< CellEditorListener>(); public TableCellEditorJComboboxHobbbies() { super(opciones); } public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { this.setSelectedItem(value); return this; } public Object getCellEditorValue() { return this.getSelectedItem(); } public boolean isCellEditable(EventObject anEvent) { return true; } public boolean shouldSelectCell(EventObject anEvent) { return true; } public boolean stopCellEditing() { synchronized (listeners) { for (CellEditorListener l : listeners) { l.editingStopped(null); } } return true; } public void cancelCellEditing() { synchronized (listeners) { for (CellEditorListener l : listeners) { l.editingCanceled(null); } } } public void addCellEditorListener(CellEditorListener l) { synchronized (listeners) { listeners.add(l); } } public void removeCellEditorListener(CellEditorListener l) { synchronized (listeners) { listeners.remove(l); } } }