我有一个Java SE项目接受将采取一些命令行参数在一个单独的线程中执行处理指定的参数。我正在使用以下焊接微线程配置依赖项进行注入
org.jboss.weld.se
weld-se-core
3.1.0.Final
org.wildfly
wildfly-microprofile-config-implementation
1.2.1
这是我的beans.xml
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
org.jboss.weld.environment.se.threading.RunnableDecorator
我的项目从以下主要类开始
@ApplicationScoped
public class Main {
@Inject
private Scheduler scheduler;
public void process(List types) throws InterruptedException {
scheduler.schedule(types);
}
public static void main(String[] args) throws InterruptedException {
SeContainerInitializer initializer = SeContainerInitializer.newInstance();
try (SeContainer container = initializer.initialize()) {
Main main = container.select(Main.class).get();
List argsList = Arrays.asList(args);
final List types = parseArguments(argsList);
main.process(types);
}
}
}
这是我的Scheduler类的代码
@ApplicationScoped
public class Scheduler {
private static final Duration DEFAULT_WAIT_TIME = Duration.ofSeconds(30);
@Inject
@ConfigProperty(name = "POOL_SIZE", defaultValue = "10")
@Getter
private int poolSize = 5;
@Inject
@ConfigProperty(name = "WAIT_DURATION", defaultValue = "PT30S")
@Getter
private String durationStr;
@Getter
private Duration waitDuration;
private ThreadPoolExecutor executor;
@Inject
private Instance exports;
@PostConstruct
public void init() {
executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(poolSize);
try {
waitDuration = Duration.parse(durationStr);
} catch (DateTimeException | NullPointerException e) {
waitDuration = DEFAULT_WAIT_TIME;
}
}
public void schedule(Collection types) throws InterruptedException {
if (types != null && !types.isEmpty()) {
//Spawn a new thread for each type
for(String type : types) {
ExportRunner runner = exports.get();
runner.setType(type);
executor.submit(runner);
}
} else {
throw new IllegalArgumentException("No FileTypes provided. Not performing export");
}
//Wait until every thread has completed
while(getTotalThreads() > 0) {
Thread.sleep(waitDuration.toMillis());
}
//shutdown executor which effectively ends the program
executor.shutdownNow();
}
public int getTotalThreads() {
return getActiveCount() + getQueueSize();
}
public int getActiveCount() {
return executor.getActiveCount();
}
public int getQueueSize() {
return executor.getQueue().size();
}
}
这是Runnable的骨架
@Dependent
public class ExportRunner implements Runnable {
@Setter
private FileType type;
//Has a custom producer and disposer
@Inject
@SEDataSource
private EntityManager em;
//Has a custom producer and disposer
@Inject
@SEDataSource
AlertService alertService;
//Has a custom producer and disposer
@Inject
@SEDataSource
HistoryService historyService;
@PostConstruct
private void init() {
//Set to same entity manager so that
//everythings happen inside single transaction
alertService.setEm(em);
historyService.setEm(em);
}
@PreDestroy
public void cleanup() {
log.info("ExporterRunner @PreDestroy was called");
}
public void run() {
try {
//do processing
} finally {
log.info("Processing Complete");
}
}
}
我遇到的问题是注入的对象(Runnable和包含的服务和EntityManager)并且在所有线程都已完成并执行executor.shutdown()命令之前永远不会被释放。
我相信,由于Runner被标记为@Dependent,它正在使用注入它的Object的Scope;这将使它成为@ApplicationScoped。我尝试使用@ThreadScoped(org.jboss.weld.environment.se.contexts.ThreadScoped)标记该类,如下所示
@ThreadScoped
public class ExportRunner implements Runnable {
...
}
但这会导致以下异常
org.jboss.weld.contexts.ContextNotActiveException: WELD-001303: No active contexts for scope type org.jboss.weld.environment.se.contexts.ThreadScoped
我觉得我需要使用@ActivateThreadScope(org.jboss.weld.environment.se.contexts.activators.ActivateThreadScope)注释,但我还没有找到任何如何使用它的示例。有谁知道我如何使我的Runnable不是@ApplicationScoped?