ServletContextListenerのcontextDestroyedにおけるポイント1とポイント2を通過するための設定やコーディングは?

このQ&Aのポイント
  • Tomcat上で動作するServletContextListenerImplのcontextDestroyedメソッド内の処理において、ポイント1とポイント2を確実に通過するにはどのような設定やコーディングが必要でしょうか?
  • ServletContextListenerImplのcontextDestroyedメソッド内の処理において、ポイント1とポイント2を通過するためには、ThreadManagerクラスとメソッドの使い方を適切に設定する必要があります。
  • contextDestroyedメソッド内の処理には、ThreadManagerクラスのstopメソッドを呼び出してスレッドを停止させ、isAliveメソッドでスレッドが停止するまで待機する必要があります。
回答を見る
  • ベストアンサー

ServletContextLisntener#contextDest

ServletContextLisntener#contextDestroyedついて 下記の様なコードがあったとします。 Tomcat上で動くServletContextListenerImpl#contextDestroyed内の処理にて ポイント1とポイント2を確実に通過するには どのような設定orコーディングが必要ですか? ※宿題ではありません。月曜に製造完です。(..); class ThreadManager {   private static final ThreadManager manager = new ThreadManager();   private final Thread t;   private boolean isStop;   pulbic ThreadManger () {     isStop = false;     final Thread t = new Thread () {       public void run () {         for ( ; ! this.isStop ; ) {           Thread.sleep(300000);         }       }       //ポイント1     }     t.start();     this.t = t;   }   public static ThreadManager getInstance () {     return manager;   }   public void stop () {     this.isStop = true;   }   public void isAlive () {     return this.isAlive();   } } public class ServletContextListenerImpl implements ServletContextListener {   public void contextInitialzed () {}   public void contextDestroyed () {     final ThreadManager manager = ThreadManager.getInstance();     manager.stop();     while (manager.isAlive()) {       //Thread.sleep(2000)する     }     //ポイント2   } }

  • Java
  • 回答数2
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
  • root139
  • ベストアンサー率60% (488/809)
回答No.2

> ServletContextListenerImpl#contextInitialzed > がコールされ数十秒でスレッドが強制終了されて > ServletContextListenerImpl#contextDestroyed > のポイント2を通過できません contextInitialzed は起動時、contextDestroyed は終了時に呼ばれるはずですが、 ・Eclipse を使って Tomcat を起動した場合には両方とも正常に呼ばれる ・Tomcat 単独で動かした場合には終了時に contextDestroyed が呼ばれていない という事ででしょうか? これらをどうやって確認したのでしょう? catalina.out などのへの出力を見たのでしょうか? 基本的にはTomcatの起動の仕方によって変わることは無いと思います。 ただし、JVMが強制終了させた場合などは contextDestroyed が呼ばれないことはありえます。例えば、linuxで kill -KILL によってTomcatの実行JVMを終了させた場合は呼ばれないと思われます。 > 基本的にinterruptするのではなく、 > 質問で言えばsleep中(処理中)とし > 処理を終えたら次の処理はせず安全に停止する interrupt を使ってもこのような動作はできます。 というか、このような動作をさせるのが interrupt の最も一般的な使い方だと思います。 sleep や wait の最中であれば、InterruptedException が発生しますが、それ以外であれば、Thread.isInterrupted() でtrueが帰るようになるだけです。 例) ------------------------------------------ public void run () {  while (!Thread.currentThread().isInterrupted()) {   // ・   // ・   // ・   try {    Thread.sleep(300000);   } catch (InterruptedException e) {    Thread.currentThread().interrupt(); // 割り込みフラグを立て直す    // sleep 中に interrupt された場合の処理   }  } } ---------------------------------------------- http://www.ibm.com/developerworks/jp/java/library/j-jtp05236/

その他の回答 (1)

  • root139
  • ベストアンサー率60% (488/809)
回答No.1

細かいスペルミスやセミコロンや例外処理の記述漏れなどを修正したとしても、このコードはコンパイルエラーになるのでは? さらには根本的にスレッドセーフになっていません。 以下、スペルミスなど以外の問題点を書きます。 1. ポイント1の場所  ポイント1はどのメソッドにも含まれていないので、どうやっても通過しません。  強いて言えば、ポイント1にフィールド定義などを書いた場合はオブジェクトが生成されたタイミングで実行されることにはなります。 2. isStop  無名クラス内で isStop を参照していますが、this は無名クラス自身のオブジェクトを指してしまいますので、単に isStop とするか ThreadManager.this.isStop としなければいけません。  また、isStop を複数のスレッドから参照・変更しようとしているようですが、同期化もされおらず volatile でもないフィールドは正しい値が見えない可能性が有ります。  キャンセルには interrupt を使うのが定石です。 http://www.itarchitect.jp/technology_and_programming/-/10795-5.html  interrupt を使うのが難しければ、Thread を無名クラスではなく名前を持った内部クラスとして定義し、その中に isStop を持たせて、同期化か volatile にすれば一応スレッドセーフにはなると思います。isStop が false になっても sleep が終わるまではチェックされませんし、お勧めはしませんが。 3. isAlive() > public void isAlive() { > return this.isAlive(); > } void 型のメソッドで自分自身の呼出し結果を返そうとしても出来ないですよね。 また、 > while (manager.isAlive()) { ・・・ も void 型のメソッドではコンパイルエラーになりますよね。 ただし、戻り値を boolean に変えても、無限再帰に陥るだけですが・・・。  下記のようなコードにするつもりで書き間違えたのかも知れませんが、これでもスレッドセーフの問題は残りますし、isStop が false になっていても、スレッドはまだ sleep 中かも知れません。 public boolean isAlive() {  return !this.isStop; // ※ これもスレッドセーフではない! } 4. ServletContextListenerImpl の各メソッドのシグネチャー  ServletContextListenerImpl の各メソッドは ServletContextListener のメソッドを実装しようとしているのだと思いますが、引数が違います。 http://mergedoc.sourceforge.jp/tomcat-servletapi-5-ja/javax/servlet/ServletContextListener.html 両方とも ServletContextEvent を引数に取らないと、オーバライドした事になりません。 以上の他にも、スペルミスなどはいろいろ有るようですので修正が必要です。  ポイント2を通す方法、というよりこれらプログラムを動かす方法ですが、 web.xml でこのリスナーに登録すればよいかと。 http://www.techscore.com/tech/J2EE/Servlet/7.html ただし、他のどこかで ThreadManager をロードするようにしていなければ、ThreadManager で定義したスレッドは、Webアプリケーションがシャットダウンするときに始まってすぐにストップされることになるでしょう。 また、isAlive の実装次第では manager の stop 待ちのループを while ではなく、for を使って回数制限したほうが良いかもしれません。  for (int i = 0; i < 10 && manager.isAlive(); i++) {   //Thread.sleep(2000)する  } このようなスレッドの終了待ち処理も、出来れば Thread.join(long) を使うような形に持っていった方が良いとは思いますが。 ちなみにJavaのスレッドプログラミングについては下記の書籍が参考になると思います。 http://www.amazon.co.jp/dp/4797337206

参考URL:
http://www.ibm.com/developerworks/jp/java/library/j-jtp0618/
public_sa
質問者

補足

遅くなり申し訳ありません。 記述ミスや抜けなど読み取っていただき しかも的確なアドバイスをいただきありがとうございます。 もう1点質問させてください。 (再度コードを載せると長くなってしまうので このまま初回の質問のコードをベースに質問させていただきます。 すみません。) ServletContextListenerImpl#contextInitialzed (引数抜け) がサーバー(tomcat)停止時にコールされ managerが停止するまで待って 安全にスレッド停止したいというコードなのですが、 manager.stop後managerが終了するまで 数分かかる場合についての安全停止についてです。 (基本的にinterruptするのではなく、 質問で言えばsleep中(処理中)とし 処理を終えたら次の処理はせず安全に停止する) eclipseから起動したtomcatを eclipseから停止した場合 managerが停止するまで数分掛かろうが ServletContextListenerImpl#contextDestroyed のポイント2を通過できます。 しかし、 warでデプロイしたアプリを サービス登録したtomcatで稼動させ サービスを停止した場合 ServletContextListenerImpl#contextInitialzed がコールされ数十秒でスレッドが強制終了されて ServletContextListenerImpl#contextDestroyed のポイント2を通過できません この場合もポイント2を通過する方法?設定?はありませんか? 質問の仕方もへたくそで申し訳ありませんが、 宜しくお願いします。

関連するQ&A

  • Javaのスレッドに関して質問です

    Assistantクラスを使い待機状態と再開を確認できるプログラムの作成 loafとrestartメソッドを設ける workメソッドが呼ばれる度loafを呼び出す Managerクラスを定義 checkメソッドを設け、Assistantをcheckし続ける loaf状態ならrestartさせる (Managerクラスはデーモンスレッド) ということなんですが、いまいちうまくいきません さぼっても復帰してくれません public class Assistant implements Runnable { private String name; private Chore c; public Assistant(String name, Chore c) { this.name = name; this.c = c; } public void run() { work(); } public void work() { while (true) { synchronized (c) { if (c.doEnd()) break; System.out.println(name + " : " + c.digest()); loaf(); } } } public synchronized void loaf() { try { c.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void restart() { c.notify(); } } public class Chore { private String name; private int step; private int id; public Chore(String name) { this.name = name; this.step = this.name.length(); this.id = 0; } public synchronized String digest() { String message = "" + id + name.charAt(id); try { Thread.sleep(500); } catch (InterruptedException ie) { } id++; return message; } public synchronized boolean doEnd() { return id >= step; } } public class Manager extends Thread { private String name; private Assistant a; public Manager(String name) { this.name = name; } public void run() { check(); } public void check() { a.restart(); } } public class Test { public static void main(String[] args) { Chore[] ch = { new Chore("掃除"), new Chore("プリント印刷"), new Chore("出欠データ入力") }; Assistant[] a = { new Assistant("あ", ch[0]), new Assistant("\tい", ch[1]), new Assistant("\t\tう", ch[2] }; Thread[] t = new Thread[a.length]; for (int i = 0; i < t.length; i++) { t[i] = new Thread(a[i]); } for (int i = 0; i < t.length; i++) { t[i].start(); } Manager m = new Manager("監査"); m.setDaemon(true); m.start(); for (int i = 0; i < t.length; i++) { try { t[i].join(); } catch( InterruptedException ie ) { } } }

    • ベストアンサー
    • Java
  • デッドロックに関して1

    下記のサンプルソースは、デッドロックを起こすソース なのですが、 public class Deadlock extends Thread { public static Object l1 = new Object(); public static Object l2 = new Object(); private int index; public static void main(String[] a) { Thread t1 = new ThreadA(); Thread t2 = new ThreadB(); t1.start(); t2.start(); } private static class ThreadA extends Thread { public void run() { synchronized (l1) { System.out.println("スレッド1: l1に対するロックを取得"); try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println("スレッド1: l2のロックの開放待ち"); synchronized (l2) { System.out.println("スレッド1: l1、l2に対するロックを取得"); } } } } private static class ThreadB extends Thread { 文字数オーばーのため削除 } これを参考に、Junitでデッドロックを起こすサンプルを作りたいです。 MultithreadedTestCaseと ControllableTestThreadを使い サンプルを作りたいのですが、 英語が良くわからず苦戦しております。 なにか、よいアドバイスをいただけませんでしょうか? よろしくお願いします

    • ベストアンサー
    • Java
  • ローカル変数にアクセスする複数のスレッドの振る舞いについて

    早速ではございますが、質問をさせていただきます。 以下のコード中のMonitorクラスを複数のスレッドが 共有して自由に入り込んでいるにも関わらす、 排他制御をしていないのにBROKENと表示されません。 final class Main { private final static int NUM = 10; public static void main(String[] args) { Monitor m = new Monitor(); UserThread[] ut = new UserThread[NUM]; Thread[] t = new Thread[NUM]; for(int i=0;i<NUM;i++) { ut[i] = new UserThread(m); t[i] = new Thread(ut[i]); t[i].start(); } } } final class UserThread implements Runnable { private final Monitor m; public UserThread(Monitor m) { this.m = m; } public void run() { System.out.println (Thread.currentThread().getName()+" BEGIN"); while(true) { this.m.func(); } } } final class Monitor { public void func() { int i1 = 0; int i2 = 0; i1++; i2++; if(i1 != i2) { System.out.println ("***** BROKEN ***** " +i1+"と"+i2); } } } 動作確認を2日間くらい行っているのですが、それでも BROKENと表示してくれません。javaの処理系によって 振る舞いがことなるかもしれませんので一概には言えませ んが、いったいなぜBROKENと表示しないのでしょうか? どうかご教授のほどよろしくお願いします。

    • ベストアンサー
    • Java
  • javaの同期について

    javaの同期について package rwlock; public class App1 extends Thread { static private final int REFER = 0; static private final int UPDATE = 1; static private final int[] conf1 = { REFER, REFER, REFER, UPDATE }; static private final int[] conf2 = { REFER, UPDATE, REFER, REFER }; static private MyObj0 mo = new MyObj0(); // App1 + MyObj0 int id; private int[] conf; public App1(int id, int[] conf) { this.id = id; this.conf = conf; } public void run() { long tStart = Time.current(); for (int i = 0; i < conf.length; i++) { switch(conf[i]) { case REFER: mo.refer(); break; case UPDATE: mo.update(); break; default: assert false : "internal error"; } } if (id == 1) { Time.printElapsed(tStart); } } public static void main(String[] args) { App1 th1 = new App1(1, conf1); App1 th2 = new App1(2, conf2); th1.start(); th2.start(); } } public class MyObj0 { private Object countLock = new Object(); private int count; private void enter() { synchronized(countLock) { count++; } } private void leave() { synchronized(countLock) { count--; } } public MyObj0() { count = 0; } public void refer() { enter(); Time.sleep(300); leave(); } public void update() { enter(); synchronized(countLock) { assert count == 1; } Time.sleep(500); leave(); } において、updateの実行中は、他のスレッドでもupdateもreferも実行されないが、二つのスレッドで同時にreferは実行されうるという条件を満たすにはどうしたらよいでしょうか?updateにsynchronizedをつけてみましたが、referが同時に実行されてしまいました

    • ベストアンサー
    • Java
  • javaの同期について

    javaの同期について package rwlock; public class App1 extends Thread { static private final int REFER = 0; static private final int UPDATE = 1; static private final int[] conf1 = { REFER, REFER, REFER, UPDATE }; static private final int[] conf2 = { REFER, UPDATE, REFER, REFER }; static private MyObj0 mo = new MyObj0(); // App1 + MyObj0 int id; private int[] conf; public App1(int id, int[] conf) { this.id = id; this.conf = conf; } public void run() { long tStart = Time.current(); for (int i = 0; i < conf.length; i++) { switch(conf[i]) { case REFER: mo.refer(); break; case UPDATE: mo.update(); break; default: assert false : "internal error"; } } if (id == 1) { Time.printElapsed(tStart); } } public static void main(String[] args) { App1 th1 = new App1(1, conf1); App1 th2 = new App1(2, conf2); th1.start(); th2.start(); } } public class MyObj0 { private Object countLock = new Object(); private int count; private void enter() { synchronized(countLock) { count++; } } private void leave() { synchronized(countLock) { count--; } } public MyObj0() { count = 0; } public void refer() { enter(); Time.sleep(300); leave(); } public void update() { enter(); synchronized(countLock) { assert count == 1; } Time.sleep(500); leave(); } において、updateの実行中は、他のスレッドでもupdateもreferも実行されないが、二つのスレッドで同時にreferは実行されうるという条件を満たすにはどうしたらよいでしょうか?updateにsynchronizedをつけてみましたが、referが同時に実行されてしまいました。

    • ベストアンサー
    • Java
  • hashCode

    ObjectのhashCodeはどういう規則で生成されているのでしょうか? あるオブジェクトにおいて、オブジェクトの生成順番が実行毎に同じならばhashCodeは同一になるかと思っていたのですが、どうも違うようなので気になりました。 例えば、マルチスレッドでObjectの生成順序を毎回違うよう生成しても、ob配列ojbs1,objs2中の要素のhashCode()は同じになります。 public class HashCodeMultiThreadTest {  public static void main(String[] args) {   final Object[] objs1 = new Object[20];   final Object[] objs2 = new Object[20];   int one_or_two = (int) (Math.random()*2+1);   final long sleep_time1 = 100 * one_or_two;   final long sleep_time2 = 100 * (3-one_or_two);      Thread t1 = new Thread() {    public void run() { try{     for (int i=0; i<objs1.length; i++) {      objs1[i] = new Object();      Thread.sleep(sleep_time1);     }    }catch(Exception e){}}   };   Thread t2 = new Thread() {    public void run() { try {     for (int i=0; i<objs2.length; i++) {      objs2[i] = new Object();      Thread.sleep(sleep_time2);     }    }catch(Exception e){}}   };   try {    t1.start();    t2.start();    t1.join();    t2.join();   }catch(Exception e){}   for (Object o : objs2)    System.out.println(o.hashCode());  } }

    • ベストアンサー
    • Java
  • TCP/IP通信について

    現在、以下のようにTCP/IP通信のプログラミングを行っており、 サーバ/クライアント別々に4byteのデータ送信を10msec毎に10秒間行っております。 現在、WimdowsVista-Windows7間で各々をサーバ/クライアントとして順に起動し、 相互に4byte送信しているハズが、倍の8byteや12byteとデータが連なって送信されている 事象が発生してます。 OutputStreamではwrite後にflushを行っているので、flush契機でメモリ上に蓄えられた 送信用バッファが送信されるイメージでおりますが、4byteで送信できていないように見えます。 上記について、解決方法をご存じであればご教授お願い致します。   <Server.java> ===== public class Server {  public static ServerSocket ss = null;  public static Socket soc = null;  private static InputStream is = null;  private static OutputStream os = null;  public static void main(String[] args) {      try {    // サーバソケット生成    ss = new ServerSocket(5000);    soc = ss.accept();    is = soc.getInputStream();    os = soc.getOutputStream();    Thread rcvTh = new ServerRcvThread(is);    rcvTh.start();    Thread sndTh = new ServerSndThread(os);    sndTh.start();    // 10秒スリープ    try{     Thread.sleep(10000);    } catch ( Exception e){     e.printStackTrace();    }    // スレッド停止    rcvTh.stop();    sndTh.stop();   } catch (IOException e) {    e.printStackTrace();   } finally{    try {     is.close();     os.close();     soc.close();     ss.close();    } catch (IOException e) {     e.printStackTrace();    }      }  } } class ServerSndThread extends Thread{  private static OutputStream ous = null;  ServerSndThread( OutputStream os ){   this.ous = os;  }  public void run(){   byte sndData[] = new byte[4];   sndData[0] = 0x01;   sndData[1] = 0x02;   sndData[2] = 0x03;   sndData[3] = 0x04;   try {    while(true){     // データ書込み     ous.write(sndData);     ous.flush();     System.out.println("データ送信");     // 0.01秒スリープ     try{      Thread.sleep(10);     } catch ( Exception e){      e.printStackTrace();     }    }   } catch (IOException e) {    e.printStackTrace();   }  } } class ServerRcvThread extends Thread{  private static InputStream ins = null;  ServerRcvThread( InputStream os ){   this.ins = os;  }    public void run(){   byte rcvData[] = new byte[16];   int size = 0;   try {    while(true){     // データ読込み     size = ins.read(rcvData);     System.out.println("size:"+size+"byte");    }   } catch (IOException e) {    e.printStackTrace();   }  } } =====     <Client.java> ===== public class Client {  private static Socket soc = null;  private static OutputStream os = null;  private static InputStream is = null;  public static void main(String[] args) {   try {    // ソケット生成    soc = new Socket("192.168.3.3", 5000);    is = soc.getInputStream();    os = soc.getOutputStream();    Thread rcvTh = new ClientRcvThread(is);    rcvTh.start();    Thread sndTh = new ClientSndThread(os);    sndTh.start();    // 10秒スリープ    try{     Thread.sleep(10000);    } catch ( Exception e){     e.printStackTrace();    }    // スレッド停止    rcvTh.stop();    sndTh.stop();   } catch (IOException e) {    e.printStackTrace();   } finally{    try {     is.close();     os.close();     soc.close();    } catch (IOException e) {     e.printStackTrace();    }      }     } } class ClientSndThread extends Thread{  private static OutputStream ous = null;  ClientSndThread( OutputStream os ){   this.ous = os;  }    public void run(){   byte sndData[] = new byte[4];   sndData[0] = 0x04;   sndData[1] = 0x03;   sndData[2] = 0x02;   sndData[3] = 0x01;   try {    while(true){     // データ書込み     ous.write(sndData);     ous.flush();     System.out.println("データ送信");     // 0.01秒スリープ     try{      Thread.sleep(10);     } catch ( Exception e){      e.printStackTrace();     }    }   } catch (IOException e) {    e.printStackTrace();   }  } } class ClientRcvThread extends Thread{  private static InputStream ins = null;  ClientRcvThread( InputStream os ){   this.ins = os;  }    public void run(){   byte rcvData[] = new byte[16];   int size = 0;   try {    while(true){     // データ読込み     size = ins.read(rcvData);     System.out.println("size:"+size+"byte");    }   } catch (IOException e) {    e.printStackTrace();   }  } } =====

    • ベストアンサー
    • Java
  • C++ シングルトン マルチスレッド

    標準C++でシングルトンを実装したいのですが。 class Singleton{ public: static Singleton* getInstance(){ if (_instance == NULL){ //スレッドAがこの時点で、スレッドBがNULLチェックすると破綻する _instance = new Singleton(); } return _instance; } private: Singleton(); static Singleton* _instance; }; マルチスレッドになると上記のパターンで破綻するといわれどうしたものかと考えております。 static Singleton* _instance = new Singleton(); と出来れば解決なのですが 「static const int データメンバ以外をクラス内で初期化することはできません」 とのことでそれもできず。 どのようにすればよいでしょうか。

  • Javaについて教えてください!

    public class Number{ private final String noo; private int ct; public Number(String noo){this.noo = noo;} public String getName(){return noo;} public void increment(){ct++;} public int getCount(){return ct;} public void reset(){ct = 0;} } このクラスを複数スレッドで使うためには、reset()とgetName()とgetCount()をsyncronizedで宣言すれば可能ですか?

    • ベストアンサー
    • Java
  • Threadの終了

    http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/index.html を見ると,スレッドの止め方が書いてありますが, これは,スレッドblinker内でループが回っていて初めてうまく行く, と(間違ってるかもしれませんが)理解しています. では下記のように,Thread2でループが回っていない場合は (*)の位置でThread2を止めるにはどうすればいいのか, 教えてくださる方はいらっしゃいませんでしょうか. (**)のClassAではSWTでGUIを表示させていて, それをThread1から閉じるというのが目的です. GUIを閉じない限りその先には進まないので, ループを回しThread2のrun()内で待機させることが出来なくて. public class Thread1 { Thread1(){ Thread2 t2 = new Thread2(); t2.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { } (*)ここでThread2を終了させたい. } public static void main(String args[]){ new Thread1(); } class Thread2 extends Thread { public void run() { new ClassA(); ・・・(**) } } }

    • ベストアンサー
    • Java