【问题标题】:Tapestry Hibernate session closed after exceeding ExecutorService fixed thread poolTapestry Hibernate 会话在超过 ExecutorService 固定线程池后关闭
【发布时间】:2013-11-14 21:11:54
【问题描述】:

我是 Tapestry-hibernate 用户,我遇到了一个问题,即我的会话在超过 Executors.newFixedThreadPool(1) 后仍然关闭;

我有以下代码,它将完美地适用于第一个线程,而其余线程将经历一个关闭的会话。如果我将线程池增加到 10,所有线程都将毫无问题地运行。一旦超过固定线程池,我就会收到会话关闭异常。我不知道如何打开它,因为它是由 Tapestry-hibernate 管理的。如果我使用 newCachedThreadPool,一切正常。有人知道这里会发生什么吗?

public void setupRender() {
        ExecutorService executorService = Executors.newFixedThreadPool(1);

        final ConcurrentHashMap<String, Computer> map = new ConcurrentHashMap<>();
        final String key = "myKey";

        final Date date = new Date();

        List<Future> futures = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            final int thread = i;

            Future future = executorService.submit(new Callable() {

                @Override
                public String call() {
                    try {
                        Computer computer = new Computer("Test Computer thread");
                        computer = getComputer(map, key, key, computer);

                        Monitor monitor = new Monitor();
                        monitor.setComputer(computer);

                        session.save(monitor);
                        session.flush();
                        System.out.println("thread " + thread);
                        try {
                            sessionManager.commit();
                        } catch (HibernateException  ex) {
                            sessionManager.abort();
                        } finally {
                            session.close();
                        }
                    } catch (Exception ex) {
                        System.out.println("ex " + ex);
                    }
                    System.out.println( new Date().getTime() - date.getTime());
                    return "completed";
                }                

            });
            futures.add(future);
        }

        for(Future future : futures) {
            try {
                System.out.println(future.get());
            } catch (InterruptedException | ExecutionException ex) {
                Logger.getLogger(MultiThreadDemo.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public synchronized Computer getComputer(ConcurrentHashMap<String, Computer> map, String key, String thread, Computer computer) {
        if (map.putIfAbsent(key, computer) == null) {
            session.save(computer);
        } else {
            computer = map.get(key);
        }
        return computer;
    }

【问题讨论】:

    标签: java multithreading hibernate tapestry


    【解决方案1】:

    我之前已经告诉过你了……你必须使用ParallelExecutor 或致电PerThreadManager.cleanup()。您需要了解 Tapestry-hibernate 具有 PerThread 范围的服务,如果您在正常请求/响应(或 ParallelExecutor)之外使用它们,则必须清理这些服务。

    我也不认为你应该打电话给session.close()。你应该模仿CommitAfterWorker

    它可能看起来像:

    @Inject PerThreadManager perThreadManager;
    @Inject HibernateSessionManager sessionManager; // this is a proxy to a per-thread value
    @Inject Session session; // this is a proxy to a per-thread value
    
    public void someMethod() {    
        ExecutorService executorService = ...;
        executorService.submit(new Callable() {
            public String call() {
                try {
                    Monitor monitor = ...
                    session.save(monitor);
                    session.flush(); // optional
                    sessionManager.commit();
                } catch (Exception ex) {
                    sessionManager.abort();
                } finally {
                    // this allows Session and HibernateSessionManager to
                    // clean up after themselves
                    perThreadManager.cleanup();
                }
                return ...
            }                
        });
    }
    

    如果您选择使用ParallelExecutor(和Invokable)而不是Executors.newFixedThreadPool(1),您可以删除对PerThreadManager 的引用,因为它会自动清理线程。

    【讨论】:

    • Lance,我正在使用 PerThreadManager.cleanup() ;-) 我正在扩展 WorkQueue,就像本例中所示,wiki.apache.org/tapestry/Tapestry5HowToWorkQueue 一切正常,在完成时调用清理方法。当我没有关闭连接时,我的数据库连接已经用完了,所以我发现这是我需要做的事情。我只遇到了一个问题,我将线程池限制为 1 并将 10 个任务放入线程池。一旦我运行第一个任务,我就得到了会话关闭异常。如果我使用 cachedThreadPool,没问题,所以我想了解原因。
    • 您上面的代码显示您将 Callable 提交给 Executors.newFixedThreadPool(1)。没有对WorkQueuePerThreadManager.cleanup() 的引用。你试过我建议的代码吗?
    • 今晚我会,我还没有机会尝试。我只是试图让我的示例保持简单,不认为工作队列代码与问题相关。谢谢兰斯。
    • 我想,你不需要调用session.close()。当您调用 PerThreadManager.cleanup() 时,HibernateSessionManager 会执行此操作。代码here
    • 完美运行,我不知道 ParallelExecutor,所以我认为没有理由不使用它。谢谢兰斯。
    猜你喜欢
    • 2014-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-10
    • 2014-03-10
    相关资源
    最近更新 更多