Java .parallelStream() with spring annotated methods

13,120

Solution 1

Well, I have a guess consists of several guesses:

  • You have session management policy as session-per-thread;
  • Object you wrote in example is in fact some entity that uses lazy loading;
  • processOne() method uses entity properties that are loaded lazily;
  • Because of first point, threads, started for parallelStream() has no session available (probably in ThreadLocal, don't remember how technically sessions are bound to threads);

That altogether causing the problem you have. The behavior looks quite strange to me, so I suggest to do the following:

  • Remove all lazy loading and try parallelStream() again;
  • If that succeeds, you'll have to load the entities completely before performing parallelStream().

Alternative way to go: detaching all list elements from session before doing parallelStream().

Although as Marko wrote in comments, Session is not thread-safe, so that means you have to get rid of Session usage either by removing lazy loading, or by detaching all entities from session.

Solution 2

The problem is not with parallel stream. In spring transaction is created using AOP.
When your processCollection method is executed spring create a proxy object of this and transaction is started. Calling another method in same class, spring will not run that method in New transaction even if you specified @Transaction . To get it run move that method process() to new service and then execute your problem. Your program will work fine.

Share:
13,120
VladS
Author by

VladS

Updated on June 25, 2022

Comments

  • VladS
    VladS almost 2 years

    I try using the parallelStream() in DAO with Spring @Transactional annotations and get so problem:

    @Transactional
    public void processCollection(Collection<Object> objects) {
        objects.parallelStream()
                .forEach(this::processOne);  //throw exception
    }
    
    @Transactional
    public void processOne(Object o) {
        ...
    }
    

    Works correct:

    @Transactional
    public void processCollection(Collection<Object> objects) {
        objects.stream()
                .forEach(this::processOne);  //work correctly
    }
    
    @Transactional
    public void processOne(Object o) {
        ...
    }
    

    Exception:

    org.hibernate.HibernateException: No Session found for current thread
    org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:106)
    org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:978)
    

    How can I use @Transactional annotated methods by parallelStream()?

    Update Why this happen Spring transaction manager and multithreading But I hope spring 4 with java 8 support can provide some solution for this. Any ideas?

  • Marko Topolnik
    Marko Topolnik about 10 years
    Hibernate's session is not thread-safe. The only option is detachment.
  • Alexey Malev
    Alexey Malev about 10 years
    @MarkoTopolnik Thanks Marko, didn't know that.