aperezra aperezra - 14 days ago 6
Java Question

Synchronizing a group of threads

I am writing a program in Java in where I have a

HashMap<String, Deque<Integer>> info;


My data is a list of Wikipedia pages that were visited with an hour time period, along with a count of how many times each was visited.

de Florian_David_Fitz 18
de G%C3%BCnther_Jauch 1
de Gangs_of_New_York 2
de Georg_VI._(Vereinigtes_K%C3%B6nigreich) 7
de Gerry_Rafferty 2


This data gets stored in the
HashMap
from above with the page name as key and the
Deque
updated hourly with the number of visits that hour.

I want to have one thread
ThreadRead
that reads input files and stores the info in the
HashMap
. And then one
ThreadCompute
thread for each key in the
HashMap
that consumes the associated
Deque
.

ThreadRead
needs to lock all
ThreadComputes
while active, then wake them up when finished so the
ThreadComputes
can work concurrently.

If I need a different mutex for each
ThreadCompute
then how can I keep all of them locked while
ThreadRead
works? And how can I wake up all the
ThreadComputes
from
ThreadRead
when is done?

I have used
info
as a lock for
ThreadRead
, and
info.get(key)
for each
ThreadCompute
But it is not working as I expected.

Edit:

I add some code to try to make more clear the problem. This is what I have at the moment:

HashMap<String, Deque<Integer>> info;
boolean controlCompute, control Read;


private static class ThreadRead extends Thread {

public void run() {
while(controlRead) {
try {
read();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public void read() throws InterruptedException{
synchronized(info){
while(count==numThreads){
for (File file: files){
reader.parse(file, info); // Reads the file and store the data in the Hashmap
keys=true;
while(info.getSizeDeque()>10){
count=0;
info.wait();
info.notifyAll();
}
}
}
controlRead=false;
}
}
}


private static class ThreadCompute extends Thread {

public String key;

public void run() {
while(controlCompute) {
try {
compute();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

public void compute() throws InterruptedException{
synchronized(info.get(key)){
if(count!=numThreads){
algorithms(); //Here I apply the algorithms to the integers in the deque
if(controlRead){
info.get(key).removeFirst();
count++;
if(count==numThreads){
info.notify();
info.get(key).wait();
}
info.get(key).wait();
}
if(info.isEmptyDeque(key)){
controlCompute=false;
}
}
}
}
}

Answer

Class java.util.concurrent.locks.ReentrantReadWriteLock is good for this kind of problem. There should be exactly one instance to guard the whole HashMap. The file reader needs to acquire the write lock of the ReadWriteLock because it wants to modify the map. The other threads need to each acquire their own read lock from the one ReadWriteLock.

All your threads must be careful to limit as much as possible the scope in which they hold their locks, so in particular, the file-read thread should acquire the write lock immediately before modifying the map, hold it until all modifications for one entry are complete, then release it. The other threads don't block each other, so they could in principle hold their locks longer, but doing so will block the file reader.

Comments