2017-05-30 29 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