Java EEの仕様とマルチスレッド
-
13-09-2020 - |
質問
StrutsとSpringを使用してJava EEアプリケーションを書いています。いずれかの操作では、データベース処理が重いため、パフォーマンスの問題が発生します。私が知りたいことはここでマルチスレッドを使うことができますか?Java EEの仕様では、カスタムスレッドをサーバーによって作成されたものとは別に作成できないと思います(私はWebLogicを使います)。これを通して私を送ってください。
解決
この質問はしばらく一度ポップアップします。
仕様に従って承認されていません。この1つはこれです。 q / a:J2EEの制限
言ったと言って、WorkManager
を使用して、スレッドをスパッカします。
最初のターゲットEJBがそれほど重要ではなく、ファイルシステムへのアクセスに関する最後のものは一般的な制限についての事実です。
それが役立つことを願っています。
他のヒント
Java EE環境でスレッドを作成するための推奨される方法は、EE7仕様の一部である並行性utils APIと共にあります。
この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();
}
}
.
その後、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を尋ね、それに渡すインスタンスを渡すだけです。スレッドを起動するには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が透過的なクラスタリングをサポートしたいため、ほとんどの制限があります。たとえば、これらの変更を他のサーバーに簡単にミラー化できないため、クラスタの1つのサーバーはファイルを変更しないでください。スレッドの場合、クラスタごとに1つのスレッドまたはサーバーごとにある場合は、質問があります。これらのスレッドはアプリケーションサーバーによっても簡単に監視できません。
は、通常のアプリケーションと同じように、スレッド、ソケット接続を作成する、またはJava EEサーバのファイルシステムにアクセスすることが可能であるべきです。
いくつかのスレッドを実行する必要がある場合は、簡単なコントロールプールを持つ提案(または代替方法)があります。
1 - あなたのコンテキスト(EJB)をあなたのメソッドにパラメータとして渡します(RESTエンドポイント、スケジューラー、デフォルトのメソッド)
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";
}
}
.