2017-05-30 5 views
0

私は、私のサーバーとクライアントスレッドサブクラス(シミュレーション)との間の完全な通信を達成するのに苦労しています。私は多くの記事を読んでいますが、私はスレッドの同期方法の基本的な概念が得られていないと思います。同期スレッド通信はJavaです - プリミティブ構造のみを使用します

問題:
私のサーバーは、3つのすべてのクライアントからのリクエストを受信して​​いるし、シャットダウンした後、クライアントがサーバから得た回答を印刷しています。しかし、サーバーは最初にクライアントに応答してから、他のスレッドから別の要求を受け取る必要があります。 あなたの親切な助けは本当に感謝します。
Server.java

public class Server extends Thread { 
private boolean isRunning; 
private final Map < String, List <String> > content; 
private final Queue <Request> requestQueue; 

public Server(String name) { 
    super(name); 

    isRunning = true; 
    content = new HashMap < >(); 
    generateContent(); 
    requestQueue = new LinkedList < >(); 

    Timer timer = new Timer(); 
    TimerTask timerTask = new TimerTask() { 
     @Override public void run() { 
      Runner.logf("Timer : Server shutting down...%n"); 

      isRunning = false; 

      timer.cancel(); 
     } 
    }; 

    timer.schedule(timerTask, 10 * 1000); 

    start(); 
} 

public synchronized boolean acceptRequest(Request request) { 
    if (isRunning) { 
     try { 
      Field privateClient = Request.class.getDeclaredField("client"); 
      privateClient.setAccessible(true); 
      Client tClient = (Client) privateClient.get(request); 

      requestQueue.add(request); 
      Runner.logf("Server accepted Request : %s\n", request.toString()); 
      return true; 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

    } 

    return false; 
} 

@Override public void run() { 

    synchronized(this) { 

     if (requestQueue.size() == 0) { 
      Runner.logf("Server : Request queue is empty, waiting...\n"); 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 

     while (requestQueue.size() != 0) { 
      Runner.logf("Server : Has just been notified, getting back to work...\n"); 
      Request temp = requestQueue.poll(); 

      try { 
       Field privateClient = Request.class.getDeclaredField("client"); 
       privateClient.setAccessible(true); 
       Client tClient = (Client) privateClient.get(temp); 

       Field privateMethod = Request.class.getDeclaredField("method"); 
       privateMethod.setAccessible(true); 
       String tMethod = (String) privateMethod.get(temp); 

       Field privateUri = Request.class.getDeclaredField("uri"); 
       privateUri.setAccessible(true); 
       String tUri = (String) privateUri.get(temp); 

       Field privateParameter = Request.class.getDeclaredField("parameter"); 
       privateParameter.setAccessible(true); 
       String tParameter = (String) privateParameter.get(temp); 

       List <String> tContent = content.get(tUri); 

       if (tContent == null && tUri.compareTo("Index") != 0) { 
        tUri = "404"; 
       } 


       if (tMethod.compareTo("GET") == 0) { 
        if (tUri.compareTo("Index") == 0) { 
         tContent = getKeys(); 
         tUri = "Document"; 
        } 

        Reply tRep = new Reply(tUri, tContent); 
        tClient.acceptReply(tRep); 
       } 

      } catch (Exception e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

     } 

    } 

} 

private void generateContent() { 
    String key; 
    List <String> value; 

    key = "A"; 
    value = new ArrayList < >(); 
    value.add("A1"); 
    value.add("A2"); 
    content.put(key, value); 
    key = "B"; 
    value = new ArrayList < >(); 
    value.add("B1"); 
    value.add("B2"); 
    content.put(key, value); 
    key = "C"; 
    value = new ArrayList < >(); 
    value.add("C1"); 
    value.add("C2"); 
    content.put(key, value); 
    key = "D"; 
    value = new ArrayList < >(); 
    value.add("D1"); 
    value.add("D2"); 
    content.put(key, value); 
} 

private List <String> getKeys() { 
    List <String> keys = new LinkedList <String>(); 
    for (String k: content.keySet()) { 
     keys.add(k); 
    } 
    return keys; 
} 
} 

Client.java

public class Client extends Thread { 

private final Server server; 
private final int periodOfRequests; 
private final Random random; 
private boolean firstRun; 

public Client(String name, double frequencyOfRequests, Server server) { 
    super(name); 
    firstRun = true; 
    this.server = server; 
    this.periodOfRequests = (int)(1000.0/frequencyOfRequests); 
    this.random = new Random(); 

    start(); 
} 

public synchronized void acceptReply(Reply reply) throws Exception { 
    Runner.logf("%s : Got Reply %s\n", this.getName(), reply.toString()); 
} 

@Override public void run() { 
    Request req = null; 

    synchronized(server) { 


     if (firstRun) { 
      firstRun = false; 
      Request firstReq = new Request(this, "GET", "Index", "NA"); 
      Runner.logf("%s : Sent Request %s \n", this.getName(), firstReq); 
      server.acceptRequest(firstReq); 
      server.notify(); 
     } 

     do { 

      try { 
       Thread.sleep(periodOfRequests); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      req = new Request(this, "GET", "A", "NA"); 
      Runner.logf("%s : Sent Request %s\n", this.getName(), req); 
      server.notify(); 
     } while (server.acceptRequest(req)); 

    } 
} 
} 

Runner.java

:おかげ以下

が関与しているクラスであります

public class Runner 
{ 

    private static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS ") ; 

    public static synchronized void logf (String format , Object ... args) 
    { 
    System.out.print (sdf.format(new Date())) ; 
    System.out.printf(format , args   ) ; 
    } 

    public static void main (String[] args) 
    { 
    if (args.length == 0) { args = new String [] { "1" , "2" , "0.5" } ; } 

    Server server = new Server("Server ") ; 

    for (int i = 0 ; i < args.length ; i++) 
    { 
     String name  = String.format  ("Client%02d" , i+1) ; 
     double frequency = Double.parseDouble(args[i]   ) ; 

     new Client(name , frequency , server) ; 
    } 
    } 
} 

電流出力:

04:40:23.522 Server : Request queue is empty, waiting... 
04:40:23.522 Client01 : Sent Request [Client01:GET:Index:NA] 
04:40:23.522 Server accepted Request : [Client01:GET:Index:NA] 
04:40:24.522 Client01 : Sent Request [Client01:GET:A:NA] 
04:40:24.523 Server accepted Request : [Client01:GET:A:NA] 
04:40:25.525 Client01 : Sent Request [Client01:GET:A:NA] 
04:40:25.526 Server accepted Request : [Client01:GET:A:NA]...... 

私が達成したいこと:

07:12:18.688 Server : Request queue is empty, waiting... 
07:12:19.204 Client02 : Sent request [Client02:Get:Index:NA] 
07:12:19.204 Server : Has just been notified, getting back to work... 
07:12:19.204 Server : Request [Client02:Get:Index:NA] is VALID, handling... 
07:12:19.204 Client02 : Got reply [Index:A,B,C,D] 
07:12:19.204 Server : Request queue is empty, waiting... 
+1

フォーマットはどうなっていますか?私はこれを読むことができません。 – shmosel

+0

@shmosel質問を正しい書式で更新しました。 – user3057437

答えて

1

私が「何をしたいことがちょうどあなたのServerの全体を置くことだと思いますループ内のrun()メソッド:

@Override 
public void run() { 
    synchronized (...) { 
     while (isRunning) { 
      // 
      // (check the Queue...process requests) 
      // 
     } 
    } 
} 

私はあなたのClientクラスについて同じことをする必要があると思います。

今すぐServerがキューを一度チェックした後、runメソッドが返ってスレッドが終了します。また

  • あなたは、/ etc​​/wait/notifyを使用すべきではありません。 Threadのインスタンスにあります。 Threadjoinのように、他のもののために自分自身でモニタを使用しています。

    この実装はthis.isAliveを条件this.wait呼び出しのループを使用しています。スレッドが終了すると、this.notifyAllメソッドが呼び出されます。アプリケーションではwait,notifyまたはnotifyAllThreadインスタンスに使用しないことをお勧めします。

    代わりに、private final Object monitor = new Object();のようなオブジェクトフィールドを作成し、それを同期します。必要ならばClientクラスがアクセスできるようにゲッターを作成しますが、おそらくアクセスする必要はありません。おそらく、monitor.notify();acceptRequestメソッドの中に置くだけです。

  • なぜあなたはリフレクションを使用してプライベートフィールドにアクセスしていますか? Request ??ちょうどゲッターを作る。

+0

私はあなたの指示に従いましたが、ちょっとした辛抱強さで私の問題は解決され、スレッドは適切に通信しています。 – user3057437

+0

ちょっとした問題です。サーバーが既にシャットダウンしてコンソールにステータスを記録すると、3つのクライアントすべてがもう1つの要求を送信し、プログラムは終了しません。手伝ってくれますか ? – user3057437