Java EE规范和多线程

问题描述 投票:28回答:4

我正在使用Struts和Spring编写一个Java EE应用程序。 在其中一个操作中,有大量的数据库处理,因此出现了性能问题。 我想知道的是,我可以在这里使用多线程吗? 我想Java EE规范除了Server创建的线程(我使用的是Weblogic)外,不允许创建自定义线程。请指导我完成这个任务。

java multithreading jakarta-ee
4个回答
9
投票

这个问题时不时就会冒出来。

按照规范,它是不被授权的。最好的页面是这个。QA: J2EE限制

话说回来,有一些方法可以生成线程,特别是在Weblogic中使用的是 WorkManager.

请看这些问题。

其实第一个针对的是EJB,应该没有那么大的关系,最后一个关于文件系统的访问是关于一般的限制。

希望对大家有所帮助。


64
投票

在Java EE环境中创建线程的推荐方法是使用并发利用API,它是EE7规范的一部分。

通过使用这个API,你的新线程将被创建,并由容器管理,保证所有的EE服务对你的线程都是可用的(例如安全、事务)。

下面的例子来自我自己的网站 此处此处

使用托管执行者服务

要使用ManagedExecutorService创建一个新的线程,首先创建一个实现Callable的任务对象。在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();
    }
}

然后我们需要通过将任务传递给ManagedExecutorService的submit()方法来调用它。

@Stateless
public class ReportBean {

    @Resource
    private ManagedExecutorService executorService;

    public void runReports() {
        ReportTask reportTask = new ReportTask();
        Future<Report> future = executorService.submit(reportTask);
    }
}

使用 ManagedThreadFactory

首先创建一个Runnable任务,它将定义在后台要做的工作。

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();
    }
}

4
投票

这些限制主要是因为Java EE和EJB希望支持透明的集群。例如集群中的一台服务器不应该修改文件,因为这些修改不容易被镜像到其他服务器上。对于线程来说,有一个问题是每个集群应该有一个线程,还是每个服务器应该有一个线程。这些线程也不容易被应用服务器监控。

也就是说,在Java EE服务器中应该可以像在普通应用程序中一样创建线程、套接字连接或访问文件系统。


0
投票

如果你需要运行几个线程,这里有一个建议(或替代方法),用简单控制的池子。

1 - 将你的上下文(EJB)作为参数传给你的方法(rest endpoint, scheduler, default's methods)

2 - 用互补的调度器或实体标志控制状态3 - 小心数据处理量。

4-建议。强烈建议指标、日志和测试、试验、测试。

5 - 这段代码是在SpringBoot上,但在Jboss中进行了测试(经过修改),在EJB上下文下--仔细测试。

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";
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.