Pergunta

Estou escrevendo um aplicativo Java EE usando Struts e Spring.Em uma das operações há um processamento pesado do banco de dados e, portanto, problemas de desempenho.O que eu quero saber é: posso usar multithreading aqui?Acho que a especificação Java EE não permite a criação de threads customizados além daqueles criados pelo Server (eu uso o Weblogic).Por favor, guie-me através disso.

Foi útil?

Solução

Esta questão aparece de vez em quando.

De acordo com a especificação não é autorizada. A melhor página para ver é esta: Q / A: Restrições J2EE

Dito isto, há maneiras de desovar fios, especialmente em weblogic com o WorkManager.

veja estas perguntas:

O fato de que o primeiro alvo ejb não importa muito, e o último sobre o acesso ao sistema de arquivos é sobre restrições gerais.

Espero que ajude.

Outras dicas

A maneira recomendada de criar threads em um ambiente Java EE é com a API Concurrency Utils, que faz parte da especificação EE7.

Ao utilizar esta API seu novo thread será criado e gerenciado pelo container, garantindo que todos os serviços de EE estejam disponíveis para seu thread (ex. segurança, transações).

Os exemplos abaixo foram retirados do meu próprio site aqui e aqui

Usando um ManagedExecutorService

Para criar um novo thread usando um ManagedExecutorService, primeiro crie um objeto de tarefa que implemente Callable.Dentro do método call() definiremos o trabalho que queremos realizar em um thread separado.

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

Então precisamos invocar a tarefa passando-a para o método submit() do ManagedExecutorService.

@Stateless
public class ReportBean {

    @Resource
    private ManagedExecutorService executorService;

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

Usando um ManagedThreadFactory

Primeiro, crie uma tarefa executável que definirá qual trabalho será feito em segundo plano.

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

Para obter um thread gerenciado por contêiner, simplesmente solicitamos ao ManagedThreadFactory um novo thread e passamos a ele nossa instância Runnable.Para iniciar o thread, chamamos start().

@Stateless
public class ReportBean {

    @Resource
    private ManagedThreadFactory threadFactory;

    public void runReports() {
        ReportTask reportTask = new ReportTask();
        Thread thread = threadFactory.newThread(reportTask);
        thread.start();
    }
}

Essas restrições estão em vez porque Java EE e EJB querem suportar agrupamento transparente.Por exemplo, um servidor de um cluster não deve modificar arquivos porque essas alterações não podem ser facilmente espelhadas para outros servidores.Para tópicos, há a pergunta se deve haver um thread por cluster ou servidor.Esses tópicos também não podem ser facilmente monitorados pelo servidor de aplicativos.

Dito isto, deve ser possível criar threads, conexões de soquete ou acessar o sistema de arquivos em um servidor Java EE como em um aplicativo normal.

Se você precisar rodar vários Threads aqui vai uma sugestão (ou alternativa) com pool de controles simples:

1 - Passe seu contexto (EJB) como parâmetro para seu método (endpoint de descanso, agendador, métodos padrão)

2 - Controle o estado com sinalizadores complementares de agendador ou entidade 3 - Cuidado com o volume de dados/processamento

4 - Recomendações:Métricas, registros e testes, testes, testes são fortemente recomendados

5 - Este código está no SpringBoot mas foi testado no Jboss (com modificações) no Contexto EJB - Teste com cuidado

6 - Utilize/modifique como desejar:(enviar sugestões/comentários)

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";
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top