3

1秒ごとに小さな文字列を送信して、サーバーへのソケット接続をチェックするスレッドクラスを作成しました。

begin()メソッドはスレッドを実行します。

接続が失われた後、スレッドは再接続を試みます。

begin()私の質問は、私が行ったようにメソッド内のスレッドで再実行してもよいかどうかですrun()(以下を参照)。

public void begin() {  
   Check = new Thread(this);
   Check.start();
}

@Override
public void run() {
   Thread thisThread = Thread.currentThread();
   while (Check==thisThread) {
      try {
         oos.writeObject("a");
         // oos.flush();

         synchronized (this) {
            while (pleaseWait) {
               try {
                  System.out.println("waiting");    
                  wait();
                  System.out.println("not waiting");      
               } 
               catch (Exception e) {
                  System.err.println("Thread is interrupted: "+e.getMessage());
               }
            }
         }
         sleep(1000);
         } catch (Exception ex) {
              v = new Visual("The connection is lost. The system will try to reconnect now.");
              this.end();
              try {
                 Server=ClientLogin.checkingServers(); //returns the reachable server string address
                 socket = new Socket(Server, ServerPort);
                 System.out.println("Connected: " + socket);
                 oos = new ObjectOutputStream(socket.getOutputStream());
                 begin();
                 v = new Visual("The system is reconnected.");
              }
              catch(UnknownHostException uhe){  
                 System.out.println("Host unknown: " + uhe.getMessage());
                 v = new Visual("The system has failed to reconnected.");
              }
              catch (IOException ioe) {
                 System.out.println("The system cannot connect to servers: " + ioe.getMessage());
                 v = new Visual("The system has failed to reconnected.");
              }
              catch (Exception e) {
                 System.out.println("The system has failed to reconnect: " + e.getMessage());
                 v = new Visual("The system has failed to reconnected.");
              }
          }
   }
}

public void end() {
   Check = null;
}
4

3 に答える 3

2

それがうまくいかない理由はわかりませんが、ちょっと面倒に見えます。新しいスレッドが現在の値を上書きする場合に備えて、ループが常に現在の値を読み取るようCheckに宣言する必要がある場合があります。volatile

IMHOのより良いアプローチは、これらのスレッドの1つを開始する役割を果たし、それがThread.join()終了するのを待つために使用する別個の「スーパーバイザー」スレッドであり、その時点で再度開始できます。

このようにして、メインスレッドのロジックは、「自己認識」を必要とせずに、本来の目的に正確に集中できます。

于 2012-09-02T21:21:03.593 に答える
1

まず、コードはスレッドセーフではありません。「チェック」フィールドは、あるスレッドによって書き込まれ、別のスレッドによって読み取られますが、同期されていません。新しく開始されたスレッドが「Check」の更新された値を確認するという保証はありません。つまり、「Check == thisThread」をチェックするときに新しいスレッドが古いスレッドの参照を取得し、間違ったことを実行します。

この特定の問題は、「チェック」フィールドを揮発性にすることで修正できます。更新されると、すべてのスレッドに新しい値が表示されるようになります。

run()メソッドで「begin()」を呼び出すことは「間違っている」わけではありません。ただし、ここで再帰呼び出しを効果的に作成したため、お勧めしません。それを間違えて無限ループに陥る可能性は十分にあります。以下のシンプルなデザインをお試しください。再帰の代わりにwhileループを使用します。

package com.thinkinginobjects;

public class HeathChecker {

public void run() {
    while (true) {
        boolean success = checkHeath();
        if (!success) {
            //log and re-establish connection
        } else {
            Thread.sleep(1000);
        }
    }
}

private boolean checkHeath() {
    try {
        oos.writeObject("a");
        return true;
    } catch (Exception ex) {
        return false;
    }
}

}

于 2012-09-02T23:14:48.013 に答える
0

大丈夫ですが、なぜ毎回スレッドを開始する必要があるのですか?TimerとTimerTaskを使用する方が良いのではないですか?

http://docs.oracle.com/javase/6/docs/api/java/util/TimerTask.html

http://docs.oracle.com/javase/6/docs/api/java/util/Timer.html

于 2012-09-02T21:16:57.743 に答える