我需要创建一个回显服务器来回显打印请求的字符串。一个线程(客户端)调用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”异常,这是因为每个线程试图从请求队列中删除元素而不添加任何内容)是我需要处理同步问题,因为队列在多个线程之间共享。在试图找出同步时我很迷茫。有没有人有一些可以帮助我的提示?任何帮助表示赞赏!
答案 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();
}