Java EE规范和多线程
-
13-09-2020 - |
题
我正在使用Struts和Spring编写Java EE应用程序。在其中一个操作中,存在重大数据库处理,因此性能问题。我想知道的是我可以在这里使用多线程吗?我认为Java EE规范不允许与服务器创建的那些分开自定义线程(我使用WebLogic)。请通过此引导我。
解决方案
这个问题偶尔弹出一次。
根据它没有授权的规范。看起来最好的页面是这个: q / a:j2ee限制
所说,有些方法可以在WebLogic中使用WorkManager
产生方法。
第一个目标EJB的事实是不重要的,而且关于对文件系统的访问的最后一个是关于一般限制。
希望它有所帮助。
其他提示
在Java EE环境中创建线程的推荐方法,是Concurrency Utils API,它是EE7规范的一部分。
通过使用此API,将创建新线程,并由容器管理,保证您的线程(例如安全性,事务)提供所有EE服务。
下面的示例是从我自己的网站 这里
使用ManagedExecutorService
使用ManagedExecutorService创建一个新线程,首先创建一个实现可调用的任务对象。在Call()方法中,我们将定义我们希望在单独的线程中执行的工作。
public class ReportTask implements Callable<Report> {
Logger logger = Logger.getLogger(getClass().getSimpleName());
public Report call() {
try {
Thread.sleep(3000);
catch (InterruptedException e) {
logger.log(Level.SEVERE, "Thread interrupted", e);
}
return new Report();
}
}
.
然后我们需要通过将ancomedExecutorService的Subment()方法传递给您来调用任务。
@Stateless
public class ReportBean {
@Resource
private ManagedExecutorService executorService;
public void runReports() {
ReportTask reportTask = new ReportTask();
Future<Report> future = executorService.submit(reportTask);
}
}
.
使用ManageDthreadFactory
首先创建一个可追踪任务,该任务将定义背景中要完成的工作。
public class ReportTask implements Runnable {
Logger logger = Logger.getLogger(getClass().getSimpleName());
public void run() {
try {
//do your background task
Thread.sleep(10000);
} catch (InterruptedException e) {
logger.log(Level.SEVERE, "Thread interrupted", e);
}
}
}
.
要获取容器托管线程,我们只需向新线程询问ManageDthreadFactory,并将其传递它的runnable实例。启动我们调用start()的线程。
@Stateless
public class ReportBean {
@Resource
private ManagedThreadFactory threadFactory;
public void runReports() {
ReportTask reportTask = new ReportTask();
Thread thread = threadFactory.newThread(reportTask);
thread.start();
}
}
. 这些限制主要是因为Java EE和EJB想要支持透明群集。例如,群集的一台服务器不应修改文件,因为这些更改无法轻易镜像到其他服务器。对于线程,如果每个群集或每个服务器应该有一个线程,则存在问题。应用服务器也无法轻易监视这些线程。
所说,应该可以在正常应用程序中创建线程,套接字连接或在Java EE Server中访问文件系统。如果您需要运行多个线程,这里是一个简单控制池的建议(或替代方式):
1 - 将上下文(EJB)传递给您的方法(REST Endpoint,Scheduler,默认方法)
2 - 用互补调度程序或实体标志控制状态 3 - 小心数据/处理量
4 - 建议:指标,日志和测试,测试,测试,测试都是强烈推荐的
5 - 此代码在SpringBoot上,但在EJB上下文下的JBoss(具有修改)中进行了测试 - 仔细测试
6 - 根据需要使用/修改:(发送建议/评论)
baseControlexecutor.java
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class BaseControlExecutor {
private final ScheduledThreadPoolExecutor poolExec = new ScheduledThreadPoolExecutor(2);
public void execWithTimeout(final Runnable runnable, long timeout,
TimeUnit timeUnit) throws Exception {
execWithTimeout(new Callable<Object>() {
@Override
public Object call() throws Exception {
runnable.run();
return null;
}
}, timeout, timeUnit);
}
public <T> T execWithTimeout(Callable<T> callable, long timeout, TimeUnit timeUnit) throws Exception {
final Future<T> future = poolExec.submit(callable);
try {
return future.get(timeout, timeUnit);
} catch (TimeoutException e) {
future.cancel(true);
throw e;
} catch (ExecutionException e) {
Throwable t = e.getCause();
if (t instanceof Error) {
throw (Error) t;
} else if (t instanceof Exception) {
throw (Exception) t;
} else {
throw new IllegalStateException(t);
}
}
}
}
.
endpointcontrolrest.java
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@RestController
@RequestMapping(value = "/report")
@Api(tags = "Endpoint of Future")
public class EndpointControlRest extends BaseControlExecutor {
Logger logger = LoggerFactory.getLogger(EndpointControlRest.class);
//single metric of execution
protected final AtomicLong counter = new AtomicLong();
@GetMapping(path = "/withThread", produces = { "application/json" })
@ApiOperation(value = "Return Hello count.")
public String greeting() {
Long countRunner = counter.incrementAndGet();
String json = ""; //or EJB context to use in Thread - becareful
new Thread(() -> {
try {
execWithTimeout(new Runnable() {
@Override
public void run() {
Instant start = Instant.now();
logger.info("Report init - " + countRunner);
//generating reports
generateBackgroundReport(json);
logger.info("Report End - " + countRunner);
Instant finish = Instant.now();
long timeElapsed = Duration.between(start, finish).toMillis();
logger.info("###DEBUG - " + countRunner + " - OK |Time exe: " + timeElapsed);
}
}, 120, TimeUnit.SECONDS);
} catch (TimeoutException e) {
logger.info("###DEBUG - " + countRunner + " - Timeout - " + e.getMessage());
} catch (Exception e) {
logger.info("###DEBUG - " + countRunner + " - Exception - " + e.getMessage());
}
}).start();
logger.info("####DEBUG - Rest call released");
return "Hello " + countRunner;
}
public String generateBackgroundReport(String json){
//simulating work
Long x = 0L;
for(Long i = 0L; i < 1000000000L; i ++){
x = i + 1;
}
logger.info("####DEBUG -report: " + x);
return "OK";
}
}
.