【问题标题】:Java multiple thread synchronizationJava多线程同步
【发布时间】:2013-11-20 22:25:19
【问题描述】:

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

其中一个步骤是使队列静态化,以便在线程之间共享它,我通过简单地替换来做到这一点:

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

with(不确定是否正确)

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

【问题讨论】:

    标签: java multithreading synchronization queue echo


    【解决方案1】:

    问题是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();
    
    }
    

    【讨论】:

    • +1 对于BlockingQueue(不是ConcurrentBlockingQueue btw)。一个易于使用的实现是LinkedBlockingQueue
    • 谢谢!这很有帮助!我有一个错误:cannot find symbol symbol : method isInterrupted() 我是否必须包含任何内容才能使此功能正常工作?
    • @user2125844 isInterrupted() 是来自java.lang.Thread 的方法;我的代码扩展了Thread,而不是Runnable
    • @user2125844 还有,你可能想看看我所做的一些修改,以更好地处理被打断的可能性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    • 1970-01-01
    相关资源
    最近更新 更多