アプリケーションの実行中に常に実行されるスレッドを作成する方法
-
05-07-2019 - |
質問
編集:
私は今、問題がに関連していると確信しています
while(true)
ループは、コメントアウトした他のすべてのコマンドを保持し、アプリケーションは添付の例外なしでデプロイされます。それがどれほど重要かはわかりませんが、私の ServletContextListener
の実装は次のようになります:
パブリッククラスBidPushServiceはServletContextListener {
を実装します
public void contextInitialized(ServletContextEvent sce) {
//Some init code not relevant, omitted for clarity
BidPushThread t= new BidPushThread();
t.setServletContext(sce.getServletContext());
t.run();
}
したがって、アプリのデプロイ時にスレッドが実行されるようになりましたが、 while
ループがコメント化されているため、実際の意味はありません。
アプリケーションの読み込み時にスレッドをバックグラウンドで実行し、常に(タイムアウトなしで)オブジェクトの特定のキューをチェックする必要があります。もちろん、オブジェクトがあると、「それらを処理します」。その後、キューのチェックを続けます。
現在、 ServletContextListener
インターフェースを実装しており、アプリのロード時に呼び出されています。その中で、いくつかのメンテナンスを行い、 java.lang.Thread
から継承したスレッドを開始します。
ここからが私の問題の始まりです(またはそう思います)。 run()
メソッドには、
while (true) {
//some code which doesn't put the thread to sleep ever
}
サーバーにアプリをデプロイしようとすると、 java.util.concurrent.TimeOutException
が発生します。
私は何を間違えていますか?
常に実行されているスレッドはありませんか?アプリが削除されると、そのスレッドは ServletContextListener
の対応するイベントによって停止されます。
本当にキューを遅滞なくチェックし続けるものが本当に必要です。
ご協力いただきありがとうございます!
編集:これはスタックトレースです
GlassFish: deploy is failing=
java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source)
at java.util.concurrent.FutureTask.get(Unknown Source)
at com.sun.enterprise.jst.server.sunappsrv.SunAppServerBehaviour.publishDeployedDirectory(SunAppServerBehaviour.java:710)
at com.sun.enterprise.jst.server.sunappsrv.SunAppServerBehaviour.publishModuleForGlassFishV3(SunAppServerBehaviour.java:569)
at com.sun.enterprise.jst.server.sunappsrv.SunAppServerBehaviour.publishModule(SunAppServerBehaviour.java:266)
at org.eclipse.wst.server.core.model.ServerBehaviourDelegate.publishModule(ServerBehaviourDelegate.java:948)
at org.eclipse.wst.server.core.model.ServerBehaviourDelegate.publishModules(ServerBehaviourDelegate.java:1038)
at org.eclipse.wst.server.core.model.ServerBehaviourDelegate.publish(ServerBehaviourDelegate.java:872)
at org.eclipse.wst.server.core.model.ServerBehaviourDelegate.publish(ServerBehaviourDelegate.java:708)
at org.eclipse.wst.server.core.internal.Server.publishImpl(Server.java:2690)
at org.eclipse.wst.server.core.internal.Server$PublishJob.run(Server.java:272)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
マイコード:
public class BidPushThread extends Thread {
private ServletContext sc=null;
@Override
public void run() {
if (sc!=null){
final Map<String, List<AsyncContext>> aucWatchers = (Map<String, List<AsyncContext>>) sc.getAttribute("aucWatchers");
BlockingQueue<Bid> aucBids = (BlockingQueue<Bid>) sc.getAttribute("aucBids");
Executor bidExecutor = Executors.newCachedThreadPool();
final Executor watcherExecutor = Executors.newCachedThreadPool();
while(true)
{
try // There are unpublished new bid events.
{
final Bid bid = aucBids.take();
bidExecutor.execute(new Runnable(){
public void run() {
List<AsyncContext> watchers = aucWatchers.get(bid.getAuctionId());
for(final AsyncContext aCtx : watchers)
{
watcherExecutor.execute(new Runnable(){
public void run() {
// publish a new bid event to a watcher
try {
aCtx.getResponse().getWriter().print("A new bid on the item was placed. The current price "+bid.getBid()+" , next bid price is "+(bid.getBid()+1));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
};
});
}
}
});
} catch(InterruptedException e){}
}
}
}
public void setServletContext(ServletContext sc){
this.sc=sc;
}
}
フォーマットの混乱はごめんなさい。ただし、「4スペースずつコードをインデント」する限りは。私にはうまくいきません 編集:「BlockingQueue」について読んで実装しましたが、まったく同じ例外とスタックトレースを取得しています。 「BlockingQueue」の使用を反映するように上記のコードを変更しました
解決
コードは新しいスレッドを開始せず、同じスレッドでループを実行するため、デプロイ時にタイムアウトエラーが発生します。
スレッドを開始するには、runメソッドではなく、startメソッドを呼び出す必要があります。
public void contextInitialized(ServletContextEvent sce) {
//Some init code not relevant, omitted for clarity
BidPushThread t= new BidPushThread();
t.setServletContext(sce.getServletContext());
t.start();// run();
}
他のヒント
要約:
- このスレッドをデーモンスレッドまたはユーザースレッドとしてマークします。の Java仮想マシンは、 実行中のスレッドのみがすべてデーモンです スレッド。
- このメソッドは、スレッドを開始する前に呼び出す必要があります。
- このメソッドは、まずこのスレッドのcheckAccessメソッドを呼び出します
引数なし。これにより、 SecurityExceptionをスローします(
現在のスレッド)。
要約:多くの場合、私たちは本当に バックグラウンドスレッドを作成したい シンプルで定期的なタスクを 応用。 setDaemon()メソッド としてスレッドをマークするために使用できます 殺すべきデーモンスレッド 他にない場合は破棄されます アプリケーションスレッドは残ります。通常は、 Javaインタープリターは引き続き実行されます すべてのスレッドが完了するまで。しかし デーモンスレッドが唯一の場合 スレッドはまだ生きています、インタプリタ 終了します。
これは非常に悪い考えです。正当な理由なしに100%のCPU負荷が発生します。
正しい解決策は、おそらくキューが空のときにスレッドをブロックすることです。これは BlockingQueue
で簡単に実装されます。
Can't I have a thread which is always running? When the app is removed,
that thread is stopped by the corresponding event in my ServletContextListener.
&quot;そのスレッドは停止しています&quot ;?どうやって? while(true){...}ループには終了条件はありません。どうやって止めますか? Thread.stop()メソッドを使用していますか?これは安全ではなく、Java 1.1で非推奨になりました
setDaemon(true)を使用する場合、アプリサーバーの管理ツールを使用してWebアプリを停止した後、スレッドはアクティブのままになります。その後、Webアプリを再起動すると、別のスレッドが取得されます。 Webアプリケーションをアンデプロイしようとしても、スレッドは実行されたままになり、Webアプリケーション全体がガベージコレクションされるのを防ぎます。その後、次のバージョンを再デプロイすると、メモリ内のすべての追加コピーが提供されます。
ループに終了条件(たとえば、InterruptedExceptionまたはvolatile&quot; stopNow&quot;ブール値)を指定すると、この問題を回避できます。
java.langThread.setDaemon()メソッドを見てください。必要な場合があります