Glassfish 4 - 使用并发API创建管理线程 [英] Glassfish 4 - Using Concurrency API to create Managed Threads

查看:106
本文介绍了Glassfish 4 - 使用并发API创建管理线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用新的Concurrency API来注入一个 ManagedThreadFactory ,并根据 Oracle教程

I'm trying to use the new Concurrency API to inject a ManagedThreadFactory and use it per the Oracle tutorial.

以下是我正在谈论的一个例子:

Here is an example of what I'm talking about:

@Singleton
@Startup
public class Demo {
    @Resource(name="concurrent/__DefaultManagedThreadFactory") ManagedThreadFactory threadFactory;

    @PostConstruct
    public void startup() {
        threadFactory.newThread(
            new Runnable() {
                @Override
                public void run() {
                    System.out.println("Do something.");
                }
            }
        ).start();
    }
}

我使用Glassfish插件在Eclipse中开发。在进行更改后重新发布时,我总是在服务器日志中获取此行。每次调用start()我们都会出现一次:

I'm developing in Eclipse using the Glassfish plugin. When I republish after making a change, I always get this line in the server log. It appears once for every call to start() we make:

SEVERE: java.lang.IllegalStateException: Module (my application) is disabled

实际上并没有抛出IllegalStateException,只是报告已经抛出Glassfish的。应用程序正常部署,但没有任何线程启动。如果我随后重新发布和第二次,错误消失,并且线程按预期开始。

It's not actually throwing an IllegalStateException, just reporting that one has been thrown (and caught) inside Glassfish. The application deploys normally, but none of the threads start. If I subsequently republish and second time, the "error" goes away and the threads start as expected.

当我尝试将应用程序部署到真实Glassfish设置(没有Eclipse),它总是报告成功部署,并且日志不包含错误。但它仍然不启动线程(即使重复部署)。

When I try to deploy the application to a "real" Glassfish setup (without Eclipse), it always reports successful deployment, and the logs do not contain the "error". But it still does not start the threads (even with repeated deployments).

我是否正确使用Concurrency API?它可能是一个配置问题?为了记录,如果我使用ManagedExcecutorService,我会得到相同的行为。

Am I using the Concurrency API correctly? Could it be a configuration problem? For the record, I get the same behavior if I use a ManagedExcecutorService instead.

问题在几个月前被问到: Can我在Singleton Enterprise Java Bean中启动一个ManagedThread?,但它没有真正回答,我没有声望做任何事情,只能再次提问。对不起!

For the record, this question was asked a few months ago here: Can I start a ManagedThread in a Singleton Enterprise Java Bean?, but it was not really answered and I don't have the reputation yet to do anything but ask it again. Sorry!

更新:这个答案通过 Per-Axel Felth 起作用。谢谢!我对该解决方案进行了一些重构,尝试从原始应用程序逻辑中分离变通办法代码:

UPDATE: This answer by Per-Axel Felth works. Thank you! I did some refactoring of that solution to attempt to isolate the workaround code from my original application logic:

@Singleton
@Startup
public class Demo {

    @Resource(name="java:comp/DefaultManagedThreadFactory") ManagedThreadFactory threadFactory;
    @EJB private ConcurrencyInitializer concurrencyInitializer;
    @EJB private Demo self;

    @PostConstruct
    public void startup() {
        self.startThread();
    }

    @Asynchronous
    public void startThread() {
        //This line applies the workaround
        concurrencyInitializer.init();

        //Everything beyond this point is my original application logic
        threadFactory.newThread(
            new Runnable() {
                @Override
                public void run() {
                    System.out.println("Do something.");
                }
            }
        ).start();            
    }

}

 

/**
 * A utility class used to get around a bug in Glassfish that allows
 * Concurrency resources (ManagedThreadFactory, ManagedExecutorService, etc)
 * to be injected before they are ready to be used. 
 * 
 * Derived from solution by Per-Axel Felth in: https://stackoverflow.com/questions/23900826/glassfish-4-using-concurrency-api-to-create-managed-threads
 */
@Singleton
public class ConcurrencyInitializer {
    /**
     * The number of milliseconds to wait before try to 
     */
    public static final long RETRY_DELAY = 500L;

    /**
     * The maximum number of concurrency attempts to make before failing
     */
    public static final int MAX_RETRIES = 20;

    /**
     * Repeatedly attempts to submit a Runnable task to an injected ManagedExecutorService
     * to trigger the readying of the Concurrency resources.
     * 
     * @return true if successful (Concurrency resources are now ready for use),
     *         false if timed out instead
     */
    public boolean init() {
        final AtomicBoolean done = new AtomicBoolean(false);
        int i = 0;

        try {
            while (!done.get() && i++ < MAX_RETRIES) {
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        done.set(true);
                    }
                });
                Thread.sleep(RETRY_DELAY);
            }
        } catch(InterruptedException e) {
            //Do nothing.
        } 

        return done.get();
    }
}


推荐答案

与Glassfish错误有关。我前段时间遇到了同样的错误,并构建了一种解决方法。事情是,线程工厂被注入了,但如果你太早使用它,你最终会遇到一个IllegalStateException异常。

It's related to a Glassfish bug. I ran into the same bug myself some time ago and built a workaround. Thing is, the thread factory is injected alright, but if you use it "too early" you'll end up with an IllegalStateException.

我的解决方法代码如下所示。它使用注入的执行程序服务来检测何时加载应用程序,并发utils是否可用,然后执行方法 init 中的实际启动逻辑。

My workaround code is listed below. It uses an injected executor service to detect when app is loaded and concurrency utils are available and then executes the actual startup logic in method init.

@Singleton
@Startup
public class Demo {

    @Resource(name = "concurrent/__DefaultManagedThreadFactory")
    ManagedThreadFactory threadFactory;
    @Resource
    ManagedExecutorService executorService;
    @EJB
    Demo me;

    @PostConstruct
    public void startup() {

        me.waitAndInitialize();
    }

    @Asynchronous
    public Future<?> waitAndInitialize() {
        try {
            final AtomicInteger done = new AtomicInteger(0);
            int i = 0;

            while (done.intValue() == 0 && i < 20) {
                System.out.println("Is executor service up?");

                i++;

                executorService.submit(
                        new Runnable() {

                            @Override
                            public void run() {
                                int incrementAndGet = done.incrementAndGet();
                                System.out.println("Run by executorservice");
                            }
                        });
                Thread.sleep(500);
            }

            if (done.intValue() == 0) {
                Logger.getAnonymousLogger().severe("Waited a long time for the ExecutorService do become ready, but it never did. Will not initialize!");
            } else {
                init();
            }
        } catch (Exception e) {
            Logger.getAnonymousLogger().log(Level.SEVERE, "Exception in waitAndInitialize: " + e.getMessage(), e);
        }

        return new AsyncResult<>(null);
    }

    private void init() {
        threadFactory.newThread(
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("Do something.");
                    }
                }
        ).start();
    }
}

这篇关于Glassfish 4 - 使用并发API创建管理线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆