2017-05-30 59 views
0

我努力實現我的服務器和客戶端線程子類(模擬)之間的完美通信。我讀了很多文章,但我想我沒有得到如何同步線程的基本概念。同步線程通信是Java - 僅使用基本構造

問題:
我的服務器接收所有三個客戶端和關閉後的請求,客戶端打印他們從服務器得到的回答。但是服務器應該首先響應客戶端,然後應該從其他線程獲取另一個請求。 你真誠的幫助將真正被讚賞。由於

下面是其中所涉及的類別:
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「的全部s循環內的run()方法:

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

我假設你需要爲你的Client類做同樣的事情。

現在Server檢查隊列一次,然後run方法返回並且線程死亡。

另外:

  • 你不應該使用​​/wait/notify /等。在Thread的實例上。 Thread使用顯示器本身的其他東西,比如join

    此實現使用的this.wait電話空調上this.isAlive循環。當一個線程終止時,調用this.notifyAll方法。建議在Thread實例上應用程序不使用wait,notifynotifyAll

    取而代之,將對象字段設置爲private final Object monitor = new Object();,然後對其進行同步。讓一個吸氣劑讓你的Client類可以訪問它,如果你想,但他們可能不需要訪問它。您應該只需將monitor.notify();置於acceptRequest方法內。

  • 爲什麼使用反射來訪問例如Request ??只要做個吸氣劑。

+0

我遵循你的指示,只要有一定的耐心,我的問題就解決了,現在線程正在進行正確的通信。 – user3057437

+0

只是一個小問題,當服務器已經關閉並將其狀態記錄到控制檯時,所有三個客戶端都發送一個請求,程序不會終止。你能幫我嗎 ? – user3057437