我在读取器/写入器实现方面遇到问题。我应该编写一个 Reader 类,该类从控制台获取字符串并将其添加到队列中,以及一个 Writer 类,该类使用线程从同一队列中删除字符串并将其输出到控制台上。我只为一个字符串编写了我的程序(键入一个字符串,它通过队列输出该字符串(,并且运行良好。现在我正在努力使它能够输入多个字符串,按 Enter 键,阅读器然后将其添加到队列中,然后编写器显示它。如果键入了字符串quit
,则两个线程都必须停止,程序应结束。
我的读者想法看起来像这样:
Scanner k = new Scanner(System.in);
in = k.nextLine();
if(in.equals("quit"))
System.exit(0);
synchronized(q){
while(!(in.equals("quit"))){
// System.out.println(q.isEmpty());
q.enqueue(in);
in = k.next();
if(in.equals("quit"))
System.exit(0);
}
}
我的作家看起来像这样:
public void run(){
synchronized(q){
while(!q.isEmpty()){
String out = q.dequeue();
System.out.println(out);
}
}
}
我的阅读器似乎工作正常,因为我在添加到队列后内置了Sys.out.(q.isEmpty)
。它向我显示队列已满,但 Writer 类没有将任何内容输出到控制台上。编写quit
会停止程序,没有任何问题。
我认为我并不完全理解线程。我的主要方法只是创建具有Thread t1 = new Thread(new Reader(queue));
和相同Writer
线程,然后启动两个线程。
synchronized(q){
while(!(in.equals("quit"))){
// System.out.println(q.isEmpty());
q.enqueue(in);
in = k.next();
if(in.equals("quit"))
System.exit(0);
}
}
这个同步块太大了。通常,您希望同步的时间尽可能短。进去,出去。同步的时间越长,其他线程被阻塞的时间就越长。
在同步时执行用户输入是禁忌。不应阻止其他线程,因为用户是慢速打字器。
更糟糕的是,您将整个程序的循环置于同步块中。坏读者!太贪婪了。在用户输入所有输入并键入"退出"之前,它不会放弃q
锁。只有这样,它才会释放锁并让编写器继续。
while(!(in.equals("quit"))){
// System.out.println(q.isEmpty());
synchronized(q){
q.enqueue(in);
}
in = k.next();
if(in.equals("quit"))
System.exit(0);
}
作者有一个不同的致命缺陷。一旦队列为空,它就会退出。不过,队列在很多时候都是空的,不是吗?当它是作家不应该只是死。
一个快速的解决方法是将整个事情包装在一个无限循环中:
public void run(){
while (true) {
synchronized(q){
while(!q.isEmpty()){
String out = q.dequeue();
System.out.println(out);
}
}
}
}
它会让作家活着。但它也会占用CPU时间,循环数百万次,而那个的用户慢慢啄键盘。如果您检查系统监视器,您将看到程序峰值达到 100% CPU 使用率。不太好。
解决这个问题有点超出本问答的范围。简短的回答是使用 wait(( 和 notify(( 让编写器进入睡眠状态,直到有可用的内容。