2013-11-20 134 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