我很抱歉这太长了,而且可能看起来太多了,但如果你能一目了然地弄清楚什么是错的,请告诉我。
在这个程序中,我尝试在每次获取一个令牌时从键盘输入一些单词(短语)并将其分配给对象sharedStorer
(然后打印指定的值以跟踪输入的内容,因为我有一串文字分别输入)。这是由一个线程完成的(类Retriever
的线程implements
Runnable
)
另一个class TokenReader
的帖子读取sharedStorer
的值并将其打印出来。 TokenReader
等待Retriever
输入,Retriever
尝试输入时TokenReader
尚未读取前一个令牌Retriever
等待。
我的问题是,最后TokenReader
等待Retriever
已完成其任务,因此程序永远不会终止。
以下是我用来执行所需任务的所有4个类(和1个接口)。
package Multithreads;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExerciseTest {
public static void main(String[] args) {
ExecutorService app=Executors.newFixedThreadPool(2);
Storer st=new SyncStorer();
System.out.println("Operation performed\t\t Value");
try{
app.execute(new Retriever(st));
app.execute(new TokenReader(st));
}catch(Exception e){
e.printStackTrace();
}
app.shutdown();
}
}
package Multithreads;
public interface Storer {
public void set(String token);
public String get();
}
package Multithreads;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Scanner;
import java.util.StringTokenizer;
public class Retriever implements Runnable {
private Scanner scanner;
private String token;
private String currentToken;
private Storer sharedStorer;
private Random rd=new Random();
public int tokenLength=0;
public Retriever(Storer st) {
sharedStorer=st;
}
public Retriever() {
}
@Override
public void run() {
System.out.println("Enter a phrase");
scanner = new Scanner(System.in);
token=scanner.nextLine();
StringTokenizer tokenizer=new StringTokenizer(token);
while(tokenizer.hasMoreTokens())
{
tokenLength++;
currentToken=tokenizer.nextToken();
try{
Thread.sleep(10*rd.nextInt(2000));
sharedStorer.set(currentToken);
}catch(NoSuchElementException e){
e.printStackTrace();
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("Done Inputting The phrase");
}
}
package Multithreads;
import java.util.Random;
public class TokenReader implements Runnable {
private Random rd=new Random();
private Storer sharedStorer;
Retriever rtr=new Retriever();
private int count=rtr.tokenLength;
public TokenReader(Storer st) {
sharedStorer=st;
}
@Override
public void run() {
String str="null";
int i=0;
try {
while(i <= count){
Thread.sleep(15*rd.nextInt(2000));
str=sharedStorer.get();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Consumer done reading");
}
}
package Multithreads;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SyncStorer implements Storer {
private Lock accessLock=new ReentrantLock();
private Condition canInput = accessLock.newCondition();
private Condition canRead = accessLock.newCondition();
private String string="null";
private boolean isEmpty=false;
@Override
public void set(String token) {
accessLock.lock();
try
{
while(isEmpty){
System.out.println("Retriever waiting");
canInput.await();
}
string=token;
isEmpty=true;
System.out.println("Retriever inputs\t\t "+string);
canRead.signal();
}catch(InterruptedException e){
e.printStackTrace();
}finally{
accessLock.unlock();
}
}
@Override
public String get() {
accessLock.lock();
try{
while(!isEmpty)
{
System.out.println("No token to read");
canRead.await();
}
isEmpty=false;
System.out.println("TokenReader reads\t\t "+string);
canInput.signal();
}catch(InterruptedException e)
{
e.printStackTrace();
}finally{
accessLock.unlock();
}
return string;
}
}
答案 0 :(得分:8)
导致应用程序永远运行的问题是这是一个无限循环:
while(i <= count){
Thread.sleep(15*rd.nextInt(2000));
str=sharedStorer.get();
}
因为你没有递减i
。你试图用来摆脱循环的中断机制(通过例外!)也被打破了。
Thread.sleep(15*rd.nextInt(2000))
行看起来像黑客,以便在任务中断时获得InterruptedException
,但是:
Thread.interrupted()
即可。此外,方法无论如何都不可靠,因为在等待/测试它之后,可能会发生中断;即在get()
电话中。如果get()
调用永远不会返回,因为store
为空并且检索器已经结束......那么您将“永远”等待。
最后一个问题。如果希望执行程序服务中断工作线程,则需要调用app.shutdownNow()
...
如果我试图实现这一点(使用中断),我会对其进行更改,以便get
和set
不会“吞噬”中断。如果他们看到中断,他们应该:
InterruptedException
传播(在相关清理后)或