1

我想运行一些简单的后台进程计算,但我似乎无法弄清楚。不管我做什么,它都会阻塞。

public class WorkThreadManagerContextLoaderListener implements ServletContextListener {
    private Runnable runnable;
    private WorkManager workManager;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        final WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
        workManager = (WorkManager) springContext.getBean("workThreadManager");

        runnable = new WorkThreadManagerStartUp(WorkManager);

        runnable.run();
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        workManager.shutDown();
    }
}

WorkThreadManagerStartUp 存在的原因是因为我不希望它阻塞所以我将它设为 Runnable 类型,当调用 run() 时,它会启动一个 ExecutorService:

public class UnitOfWorkThreadManagerStartUp implements Runnable {
    private WorkManager workManager;

    public UnitOfWorkThreadManagerStartUp(WorkManager workManager) {
        this.workManager = workManager;
    }

    @Override
    public void run() {
        workManager.startUp();
    }
}

public class WorkThreadManager implements WorkManager {
    @Autowired
    private WorkService workService;

    private final int availableProcessors = Runtime.getRuntime().availableProcessors();
    private final ExecutorService executorService = Executors.newFixedThreadPool(4 * availableProcessors);

    @Override
    public void startUp() {
        // this method always blocks...
    }
}

但我的解决方案没有按预期工作。我在 Tomcat 7.0.30 上运行。

我想弄清楚的是如何在不停止 Web 应用程序部署的情况下在后台启动线程池,因为目前由于 startUp() 总是阻塞,它永远无法完全联机。我想简化这个解决方案,如果不需要的话,可能会删除 WorkThreadManagerStartUp 类。

编辑:

我修改了启动类

public class WorkThreadManagerStartUp implements Runnable {
    private WorkManager workManager;

    public WorkThreadManagerStartUp(WorkManager workManager) {
        this.workManager = workManager;
    }

    @Override
    public void run() {
    try {
        while (true) {
                System.out.println("Hello World!");
                Thread.sleep(1000 * 10);
            }
        } catch(InterruptedException e) {
            System.out.println(e.getMessage());
        }
    }
}

虽然这应该在它自己的线程上运行,Hello World!按预期显示多次,但不允许 Web 应用程序联机。

4

1 回答 1

1

查看您的来源,我没有看到实际创建的任何线程。通常,您会执行以下操作来分叉线程:

new Thread(new WorkThread(...)).start();

这将调用WorkThread.run()新线程中的方法。如果您使用的是ExecutorService(通常推荐使用的“手动”代码Thread),那么您将执行以下操作:

executorService.submit(new WorkThread(...));
...
// when done with the service you have to shut it down
executorService.shutdown();

如果您将您的WorkManager类注入到您的监听器类中,那么我只需submit(...)在管理器上添加一个方法,然后在监听器中执行以下操作:

workManager.submit(new WorkThread());

这意味着WorkThreadManagerStartUp该类是没有必要的。您将工作线程或工作单元提交给服务。

就 Spring 而言,我只是让你的WorkManager类实现InitializingBeanDisposableBean这样它就可以自己启动和停止它的服务。没有理由让另一个 bean 这样做。然后,您可以将管理器注入到任何想要WorkThread使用由管理器管理的类中运行的类ExecutorService

于 2012-10-10T14:00:07.240 回答