Java多线程同步

时间:2013-11-20 22:25:20

标签: java multithreading synchronization queue echo

我需要创建一个回显服务器来回显打印请求的字符串。一个线程(客户端)调用echo方法来提交要回显的字符串(所有echo方法实际上都将字符串放在作业队列中),然后一个单独的线程将字符串从队列中出列并将它们输出到屏幕。

其中一个步骤是将队列设置为静态,以便在线程之间共享它,我只需更换:

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”异常,这是因为每个线程试图从请求队列中删除元素而不添加任何内容)是我需要处理同步问题,因为队列在多个线程之间共享。在试图找出同步时我很迷茫。有没有人有一些可以帮助我的提示?任何帮助表示赞赏!

1 个答案:

答案 0 :(得分: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();

}