3

長くなりすぎて申し訳ないのですが、何がおかしいのか一目でわかる方がいらっしゃいましたら教えてください。

このプログラムでは、1 つのトークンを取得するたびにキーボードからいくつかの単語 (フレーズ) を入力し、それをオブジェクトに割り当てようとしますsharedStorer(次に、割り当てられた値を出力して、入力されたものを追跡します。個別に入力する一連の単語があるため)。 . これは、1 つのスレッド (クラスRetrieverwhichのスレッドimplements Runnable)によって行われます。

class TokenReaderの値を読み取って出力する別のスレッドがありますsharedStorerTokenReader入力を待ち、前のトークンをまだ読み取っていないRetrieverときRetrieverに入力しようとすると待機します。TokenReaderRetriever

私が持っている質問は、最後にそのタスクが完了するまで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;
}

}
4

1 に答える 1

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

最後の問題が1つあります。エグゼキュータサービスでワーカースレッドを中断する場合は、を呼び出す必要がありapp.shutdownNow()ます...


これを(割り込みを使用して)実装しようとした場合は、割り込みを「飲み込まない」ようgetに変更します。set割り込みが表示された場合は、次のいずれかを実行する必要があります。

  • 伝播を許可InterruptedExceptionする(関連するクリーンアップ後)、または
  • 例外ハンドラでスレッドの中断フラグを再度設定します。
于 2013-01-12T00:32:31.127 に答える