一般信息: 三个读取器线程以块的形式从文件中随机读取,其中每个块都有一个 ID,并且它们写入普通的 ArrayList。只要将具有所需 ID 的块添加到列表中,写入器线程就会写入输出文件。
出于这个原因,我编写了一个 BlockingChunkList,它应该同步 add() 和 getNextChunk() 方法。
它适用于我在一种情况下使用同步 + 通知 + notifyAll 和在另一种情况下使用同步列表。
当我使用 ReentrantLock 和 Condition 时,我无法做到这一点。writer-thread 只写了四个块,然后他就卡住了。
为什么它可能不起作用: 我怀疑一旦阅读器完成,作者就无法取回锁。但是我希望每次有东西要写(available = true)时,都应该调用写线程。当 available 为真时,他们似乎忽略了 hasAccess.await() 。
它应该如何工作: 读取线程仅调用 add 方法,并且仅在有要写入的内容(可用)时才释放写入线程。当 available=true 时,它们也会阻止自己。当作者通过调用 hasAccess.signalAll() 写了一些东西时,这个锁被释放。写线程只调用 getNextChunk() 方法,他在写块时释放其他线程。当 available=false 时,他会阻止自己,并被读者释放。
问题: 读取线程完成工作,写入线程只写入前 4 个块。我希望编写器总是在available=true 时被调用。
我不需要一个确切的解决方案,因为我认为我遗漏了一些东西,所以也很感激提示。所以:我错过了什么?
谢谢你
编辑:并发仅在发布的类中处理。主要方法仅启动踏板。编辑 2:这是我第一次尝试并发。我知道 ArrayList 不是线程安全的。我想通过使用 ReentrantLock 和 Condition 来理解这些概念。BASIC的想法是阻止读取器或写入器,无论可用是真还是假。
import java.util.ArrayList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BlockingChunkQueue {
private final ArrayList<Chunk> chunks;
private volatile int currentID = 0; // first ID for which the writer needs to wait
private volatile boolean available; // true if the ID is in the list
private final Lock listLock;
private final Condition hasAccess;
public BlockingChunkQueue(){
chunks = new ArrayList<>();
listLock = new ReentrantLock();
hasAccess = listLock.newCondition();
available = false;
}
/*
* While there is a chunk which might be written to the output (=correct ID) then wait for access.
* Then add the chunk and if the added chunk has the ID for which the other thread is waiting, then,
* then available = true and signal the waiting thread.
*
*
*/
public void add(Chunk chunk) throws InterruptedException{
listLock.lock();
try{
while(available){
hasAccess.await(); // reader block yourself until you get the lock back
}
chunks.add(chunk);
if(chunk.getId() == currentID){
available = true;
hasAccess.signalAll();
}
}finally{
listLock.unlock();
}
}
/*
* If the chunk is not available then wait.
* If it becomes available then increment the ID, remove it from the list, signal the reader-threads and set available false.
* return the chunk which will be written to the output.
*/
public Chunk getNextChunk() throws InterruptedException {
listLock.lock();
try{
while(!available){
hasAccess.await(); // block yourself until u can write something
}
for(Chunk c : chunks){
if(c.getId() == currentID){
currentID++;
chunks.remove(c);
hasAccess.signalAll(); //signal the readers
available = false;
return c;
}
}
}finally{
listLock.unlock();
}
return null;
}
public int getcurrentID(){ return currentID;}
public boolean isEmpty(){ return chunks.isEmpty(); }
public int size(){return chunks.size();}
}
解决方案: 处理线程没有任何问题。事实证明这是我这边的一个逻辑错误。写入线程卡住了,因为他没有机会检查必要的 ID,因为写入者随机读取块。感谢您的帮助。