2013-11-20 129 views
1

我需要創建一個echo-echo請求的字符串的echo服務器。一個線程(Client)調用echo方法來提交要回顯的字符串(所有echo方法實際上都是將字符串放在作業隊列中),然後一個單獨的線程從隊列中取出字符串並將它們輸出到屏幕。Java多線程同步

步驟之一是使隊列靜態的,以便它在線程之間共享,我只需簡單地更換這樣做:

public final Queue<String> requests = new LinkedList<String>(); 

用(不知道是否正確)

public static Queue<String> requests = new LinkedList<String>(); 

在此代碼:

public class EchoServer implements Runnable { 

//make queue a static object 
//public final Queue<String> requests = new LinkedList<String>(); 
public static Queue<String> requests = new LinkedList<String>(); 

public EchoServer() { 
    new Thread(this).start(); 
} 

//all echo does is place the string in the job queue 
public void echo(String s) { 
    requests.add(s); 
} 

public void run() { 
    for(;;) realEcho(requests.remove()); 

    //synchronized here? 
} 

private void realEcho(String s) { 
// do the real work of echo-printing 
} 

    public static void main(String[] args) { 
    System.out.println(Thread.currentThread().getName()); 
    EchoServer r1 = new EchoServer(); 
    r1.echo("HEY"); 
    Thread t1 = new Thread(r1, "manager"); 
    t1.start(); 


    EchoServer r2 = new EchoServer(); 
    r2.echo("HI"); 
    Thread t2 = new Thread(r2, "client"); 
    t2.start(); 

    } 

}

現在我的問題(除了「NoSuchElement」異常,這是因爲每個線程都嘗試從請求隊列中刪除元素而不添加任何內容)是我需要照顧同步問題,因爲隊列是在多個線程之間共享的。試圖找出同步時我很迷茫。有沒有人有一些提示可以幫助我?任何幫助表示讚賞!

回答

2

問題是LinkedList不是線程安全的。

改爲使用ConcurrentLinkedQueue

更好的是,使用BlockingQueue,它做同樣的事情,除了它提供了一個額外的方法take(),將阻塞,直到有一個項目在隊列中。這樣,它不會不斷地重新檢查隊列,消耗每個可用的備用處理器週期,以便檢查自上次檢查後最近50納秒是否添加了新項目。
例如:

public class EchoServer implements Thread { 

    public static BlockingQueue<String> requests = new LinkedBlockingQueue<>(); 

    public void echo(String s) { 
     if(isInterrupted()) throw new IllegalStateException("Queue is closing!"); 
     requests.add(s); 
    } 

    @Override 
    public void run() { 
     try(
      while(!isInterrupted() || requests.peek()!=null) 
       processEchoRequest(requests.take()); 
     } catch (InterruptedException e) {} 
    } 

    private void processEchoRequest(String s) { /* [...] */ } 

} 

在main方法的變量確實需要重命名:

public static void main(String[] args) { 

    EchoServer clientEchoServer = new EchoServer(), \ 
       managerEchoServer = new EchoServer(); 

    managerEchoServer.start(); 
    managerEchoServer.echo("HI!"); 

    Thread manager = new Thread(managerEchoServer, "manager"); 
    manger.start(); 


    clientEchoServer.start(); 
    clientEchoServer.echo("HI!"); 

    Thread client = new Thread(managerEchoServer, "manager"); 
    client.start(); 

} 
+0

+1'BlockingQueue'(它不是'ConcurrentBlockingQueue' BTW)。一個簡單的實現是使用'LinkedBlockingQueue'。 – Gray

+0

謝謝!這非常有幫助!我有一個錯誤:'找不到符號 符號:方法isInterrupted()' 我必須包括任何東西才能使此函數工作? – user2125844

+0

@ user2125844'isInterrupted()'是一個來自'java.lang.Thread'的方法;我的代碼擴展了'Thread',而不是'Runnable'。 – AJMansfield