如何避免java.util.ConcurrentModificationException

问题描述

我在此应用程序中使用了Hibernate。我正在尝试从数据库调用数据到jTable。当数据库为空时,正在编译代码,但是当我向MysqL表程序中添加数据时,抛出java.util.ConcurrentModificationException。

 public FrmMain() {
    initialize();
    getData();
 }

 public void getData() {
    
    model = (DefaultTableModel) tblBookList.getModel();
    
    List<Book> books = new ArrayList<>(bookManager.getBook());
    
    ListIterator<Book> listIterator = books.listIterator();
      
    while(listIterator.hasNext()) {
      
      Book book = listIterator.next();
      
      Object[] row = { book.getName(),book.getAuthor(),book.getPublisher(),book.getPage(),book.getTranslator(),book.getPublishYear(),book.getType()
      };
      
      model.addRow(row);
      
    }
    
}

我的数据访问代码。也许问题出在这里

public class MysqLBookDal implements IBookDal {

SessionFactory factory = new Configuration()
        .configure("MysqLHibernate.cfg.xml")
        .addAnnotatedClass(Book.class)
        .buildSessionFactory();

Session session = factory.getCurrentSession(); 

public List<Book> select() {
    
    List<Book> books = new copyOnWriteArrayList<Book>();
    
    try {
        
        session.beginTransaction();
        
        books = session.createquery("from Book").getResultList();
        
        for(Book book: books) {
            books.add(book);
        }
        
        session.getTransaction().commit();
        
    } finally {
        factory.close();
    }
    
    return books;
}

有人可以帮助我吗? 堆栈跟踪:

ERROR: Connection leak detected: there are 1 unclosed connections upon 

shutting down pool jdbc:MysqL://localhost:3306/book?useUnicode=true&useLegacyDatetimeCode=false&serverTimezone=Turkey
java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
    at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
    at com.github.bookManagementSystem.dataAccess.MysqLBookDal.select(MysqLBookDal.java:32)
    at com.github.bookManagementSystem.business.BookManager.getBook(BookManager.java:20)
    at com.github.bookManagementSystem.FrmMain.getData(FrmMain.java:98)
    at com.github.bookManagementSystem.FrmMain.<init>(FrmMain.java:90)
    at com.github.bookManagementSystem.FrmMain$1.run(FrmMain.java:76)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:316)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
    at java.desktop/java.awt.EventdispatchThread.pumpOneEventForFilters(EventdispatchThread.java:203)
    at java.desktop/java.awt.EventdispatchThread.pumpEventsForFilter(EventdispatchThread.java:124)
    at java.desktop/java.awt.EventdispatchThread.pumpEventsForHierarchy(EventdispatchThread.java:113)
    at java.desktop/java.awt.EventdispatchThread.pumpEvents(EventdispatchThread.java:109)
    at java.desktop/java.awt.EventdispatchThread.pumpEvents(EventdispatchThread.java:101)
    at java.desktop/java.awt.EventdispatchThread.run(EventdispatchThread.java:90)

解决方法

尝试使用CopyOnWriteArrayList代替ArrayList。这将允许并发修改。但是请注意,如果您要更改列表很多,这不是很有效。但是,如果您大部分时间在读书,那应该没问题。

,

ConcurrentModificationException被抛出,因为您正在将元素添加到要迭代的同一列表中。在这里:

for(Book book : books) {
    books.add(book);
}

此代码是错误的。

您可以返回Hibernate返回的List实例,也可以创建一个新列表。

您不需要使用CopyOnWriteArrayList!这是非常昂贵的数据结构。您的错误与同时修改和访问列表的不同线程无关。此外,您不需要针对数据库启动显式事务,因为您只是在阅读。整个select方法可以完全简化为:

public List<Book> select() {
    return new ArrayList<>(session.createQuery("from Book").getResultList());
}

您也不需要关闭factory

,

@DuncG可以解决您的紧迫问题。

假设您通过start.spring.io下载所需的依赖项,则使用Spring Boot可以将您的代码简化为以下代码:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface BookRepository extends JpaRepository<Book,Long> {
}

在您的服务课程中:

@Autowired //or use constructor injection
BookRepository BookRepository;

public List<Book> findAll() {
    return bookRepository.findAll();
}

JpaRepository继承了findAll()方法以及带有CRUD存储库的其他非常常见的行为。有关更多详细信息,请参见docs