除非添加print语句,否则线程同步不起作用

时间:2016-02-13 17:07:01

标签: java multithreading synchronized

我正在创建一个程序来检查字符串是否包含在目录和文本文件的树中,并且我使用了生产者 - 消费者模式。不幸的是,除非我添加一个print语句,否则我的消费者线程并不想停止。我尝试了一切 - 同步,使字段变得不稳定,但仍然无法找到问题。

public class Producer
extends Thread
{
private volatile Storage store;
private volatile Reader read;

Producer(Storage store, Reader read){
    this.read = read;
    this.store = store;
}



public void run()
{
    while (!read.isEmpty()) {

            String FileName = read.returnAllPaths().peek().getFileName().toString();
            String item = null;
            try {
                item = read.returnAllPaths().take().toString();
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            File currentFile = new File(item);
            try (BufferedReader reader = new BufferedReader(new FileReader(currentFile))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    FileAndLine current = new FileAndLine(FileName, line);
                    store.fillStore(current);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }


    }

    store.setEndOfPaths(true);
}
}
public class Consumer
extends Thread
{
private volatile Storage store;
private String clue;

public Consumer(Storage store, String clue){
    this.store = store; 
    this.clue = clue;
}

public void run()
{

    FileAndLine currentLine;

    while(!store.isEndOfPaths() || !store.isEmpty()){
        currentLine = store.depleteStore();
        System.out.println("q");
        if(currentLine.line.contains(clue))
            System.out.println(currentLine.FileName + ": " + currentLine.line);
    }
}

}
public class Storage {
private BlockingQueue<FileAndLine> Store;
private boolean full;
private volatile boolean endOfPaths;


public Storage(){
    Store = new LinkedBlockingQueue<FileAndLine>();
    full = false;
}

private boolean isFull(){
    return full;
}

public synchronized BlockingQueue<FileAndLine> getStore(){
    return this.Store;
}

public synchronized boolean isEmpty(){
    return Store.isEmpty();
}


public synchronized void setEndOfPaths(boolean set){
    endOfPaths = set;
}

public synchronized boolean isEndOfPaths(){
    return endOfPaths;
}

public synchronized void fillStore(FileAndLine line){
    while(isFull()){
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    Store.add(line);

    full = false;
    notifyAll();

    if(Store.size() == 1000){
        full = true;
    }
}

public synchronized FileAndLine depleteStore(){

    FileAndLine line;
    if(endOfPaths == true && Store.isEmpty())
    {
        return new FileAndLine("", "");
    }
    while(Store.isEmpty())
    {
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    line = new FileAndLine(Store.remove());

    if(Store.size() < 1000){
        full = false;
        notifyAll();
    }
    return line;
}

}

1 个答案:

答案 0 :(得分:0)

当你这样做时

private volatile Reader read;

这意味着Reader read 引用是易变的。这意味着当您阅读此字段时,它的访问权限是不稳定的。但是,这并不意味着引用的对象是线程安全的。您的测试是

while (!read.isEmpty()) {

并且这个测试必须是线程安全的。

注意:当您写入控制台时,您间接使用同步块,因为PrintStream的所有方法都是synchronized,并且这具有读写屏障。

  

我正在制作一个程序来检查字符串是否包含在目录和文本文件树中

String text = "looking-for";
Files.walk(Paths.get("mydir"))
        .parallel()
        .filter(p -> p.toFile().isFile())
        .forEach(p -> {
            try {
                if (Files.lines(p)
                        .anyMatch(l -> l.contains(text)) {
                    System.out.println("file " + p + " contains " + text);
                });
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

您不需要管理将工作分成多个线程并协调它们的所有处理,尤其是当您有一个数据处理任务时。