2009-04-06 24 views
3

こんにちは私は正常に動作しているGUIアプリケーションがあります。ソケットサーバーを作成しました。プログラムでServerクラスの新しいオブジェクトを作成すると、GUIアプリケーションが応答を停止します。マルチスレッドとJava Swingの問題

これは私のサーバークラスです。私の場合、私の主なアプリケーションでは

Server s = new Server(); 

が動作しなくなります。それをどのように追加すればよいですか?新しいスレッドを作る?試しました

Thread t = new Thread(new Server()); 
t.start(); 

この問題は解決しません。私はあなたの助けに感謝します。 accept()

package proj4; 

import java.net.*; 
import java.io.*; 

public class Server implements Runnable { 
    ServerSocket  serverSocket = null; 
    Socket    clientSocket = null; 
    ObjectOutputStream out   = null; 
    ObjectInputStream in   = null; 
    int    port; 
    static int   defaultPort = 30000; 
    boolean   isConnected = false; 
    Thread    thread; 
    DataPacket   packet  = null; 

    public Server(int _port) { 
     try { 
      serverSocket = new ServerSocket(_port); 
      serverSocket.setSoTimeout(1000*120); //2 minutes time out  
      isConnected = true; 
      System.out.println("server started successfully"); 
      thread = new Thread(this); 
      thread.setDaemon(true); 
      //thread.run(); 
     } catch (IOException e) { 
      System.err.print("Could not listen on port: " + port); 
      System.exit(1); 
     } 
     try { 
      System.out.println("Waiting for Client"); 
      clientSocket = serverSocket.accept(); 
      System.out.println("Client Connected"); 
      thread.run(); 
     } catch (IOException e) { 
      System.err.println("Accept failed."); 
      System.exit(1); 
     } 
     try { 
      out = new ObjectOutputStream(clientSocket.getOutputStream()); 
      System.out.println("output stream created successfully"); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     try { 
      in = new ObjectInputStream(clientSocket.getInputStream()); 
      System.out.println("input stream created successfully"); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public Server() { 
     this(defaultPort); //server listens to port 30000 as default 
    } 

    public void run() { 
     System.out.println("Thread running, listening for clients");//debugging purposes 
     while (isConnected) { 
      try { 
       packet = this.getData(); 
       Thread.sleep(0); 
      } catch(InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    public DataPacket getData() { 
     try { 
      packet = (DataPacket)in.readObject(); 
     } catch (Exception ex) { 
      System.out.println(ex.getMessage()); 
     } 
     return packet; 
    } 

    public void sendData(DataPacket dp) { 
     try { 
      out.writeObject(dp); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     try { 
      out.flush(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public void closeConnection() throws IOException { 
     out.close(); 
     in.close(); 
     clientSocket.close(); 
     serverSocket.close(); 
    } 
} 

答えて

11

潜在的に無期限にごServerコンストラクタブロック、。

Swingのプログラムについての2つのこと:

  1. は、Swingイベントスレッド内の任意の長いタスクを実行することはありません、そして、
  2. は、使用されている方法が明示的でない限り、Swingのイベントスレッド外のSwingのオブジェクトを操作行うことはありませんスレッドセーフとして文書化されています。

これは、サーバーがSwingイベントスレッドから起動されている場合、つまりボタンクリックなどで起動されている場合は、別のスレッドを生成する必要があることを意味します。サーバーオブジェクト。そうしないと、スレッドが終了するまでSwingイベントスレッドがブロックされることが保証されます。

サーバーの別のスレッドを生成してもアプリケーションが応答を停止したとしますか? Thread.start()で、run()ではないことを確認してください。そうしないと、あなた自身のスレッドで実際には「新しいスレッド」を実行して誤ってブロックすることになります。

NOTES:

  1. 私はあなたがあなたの目でThread.sleep(0);()ループを行うことを参照してください。これは何もすることが保証されていません。単一のCPUマシンを使用している場合、これはno-opとしてかなり実装されている可能性があり、同じスレッドを実行し続けることができます。
  2. 実際にisConnectedvolatileにすることをお勧めします。そうしないと、この変数の変更が、変更されたスレッド以外のスレッドから見えるという保証はありません。
  3. isConnectedをfalseに設定しないでください。run()は、JVMが停止するまで、またはそのスレッドがRuntimeExceptionを取得するまで実行されます。
  4. It is discouragedコンストラクタでスレッドを開始する。 (Java Concurrency In Practiceを参照してください)
  5. スレッドrun()の方法になるまで、ServerSocketacceptにしたくないです!それ以外の場合、コンストラクタは接続の待機をブロックし、イベントスレッドに制御を返しません!
  6. あなたのコンストラクタで次のコードを持っている:

あなたのコードは次のとおりです。あなたがthread.run()コメントアウトしていなかった

thread = new Thread(this); 
thread.setDaemon(true); 
//thread.run(); 

は、あなたがない新しいスレッドを開始しました!それを行うには、thread.start()をする必要があります。代わりに、あなたはこの新しいスレッドを実行していました(上記の理由3のために、決して停止しません)、コンストラクタを呼び出したのと同じスレッドで実行していました。あなたのコードが現在書かれている方法では、すべてのIOExceptionはログに記録されますが、それ以外の場合は飲み込まれます。任意のIOExceptioncloseConnection()には、isConnectedfalseに設定することをお勧めします。

1

サーバクラスが妥当と思われます(私は実際にはコンパイルしていませんが、それは妥当と思われます)。GUIが応答しなくなった場合、GUIスレッドは制御できません。理由を調べるには、これを作成するコード(実際の場所と動作方法)を実際に見ておく必要があります。あなたがが、確かに問題ではないのです

(new Thread(new Server()).start(); 

にそれを短縮することができますが

あなたの基本的な考え方は、権利です。ここで

思考です:時点で、あなたが作成して、すなわち、プリントや、ロギングステートメントを追加し、直接コールの後、サーバを起動

(new Thread(new Server()).start(); 
System.err.println("Got here!"); 

とあなたが見るかどうかを確認し、「ここに来ましたの!」メッセージ。そうでない場合は、GUIスレッドをブロックしています。

https://swingworker.dev.java.net/

SwingWorkerのは、おそらくクリーンなアプローチです:

+0

をし、あなたが見るかどうかを確認し、「ここに来ました!」メッセージ。そうでない場合は、GUIスレッドをブロックしています。 これが問題です。私はコードを追加し、 "Got here"というメッセージには決して行きません。この問題を解決する方法がわかりません。 – user69514

+0

さて、その呼び出しの周りに少なくともコードを表示しなければならないでしょう。このスレッドが起動しているようです。 –

+0

メインクラスにServerオブジェクトを作成しましたが、GUIはまだ動作していましたが、GUIアプリケーション内にServerオブジェクトを作成する必要がありました。 – user69514

0

あなたは、あなたが常に使用できるJavaの以前のバージョンでそれを使用する必要がある場合のJava 6で提供されてSwingWorkerのを使用することができます。あなたはここでそれについての詳細情報を見つけることができます:あなたは、その機能をラップまたは匿名内部クラスを使用する新しいServerSwingWorker内部クラスを書くことができ

http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html

+0

invokeLater()は実際に呼び出されたコードを実行します糸。しかし、SwingWorkerがOPを手助けします。 – Eddie

+0

SwingWorker solで更新されました。 only ... – Jon

4

問題は、サーバーのコンストラクタがブロックされていることです。コスコンストラクタはブロッキング呼び出しを行うべきではありません(実際には可能な限り少なくすべきです)。ブロッキング呼び出しは、run()またはrun()によって呼び出されたものによって行われる必要があります。

また、新しいThread()を作成すると、目的を持たないコンストラクタになります。

+0

OPは、スレッドを開始するために元々そのコードを使用していて、呼び出し元のスレッドでコードを意図せず実行していたに違いありません。はい、そのコードはOPのコードでは廃止されています。 – Eddie

0

少し詳しく、「新しいサーバーを()」はまだ実際のスレッドで実行されているので

new Thread(new Server()) 

が助けにはなりませんやって。

それはのようなものでなければなりません:

Thread t = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      new Server(); 
     } 
    }); 
    t.start(); 
関連する問題