Reputation: 1086
I have a test file with three lines, each line begins with a timestamp in seconds. I read this time stamp and based on it I schedule a new timer for each time stamp being read. Why, when I run the threads created in the method "processFile" mentioned below, does the console display the output of the three timers at once? I expected to see the out put of each timer separated with few seconds delay between as the time stamp of each of the three lines i read from the file are 2 seconds, 15 seconds and 7 seconds respectively? when i run the program, after few seconds i receive the below "system time" output all at once without delay separate them despite the timestamp being read from the file is different!
Kindly please let me know why what is happening and how to solve it.
//this method is being called on a worker thread
private static void processFile(File dataFile) throws IOException {
// TODO Auto-generated method stub
System.out.println(WORKER_THREAD + " started.");
logfile = new MeasurementFile(dataFile, MeasurementFile.ENCODING_UTF_8);
System.out.println("Total lines in the file: " + logfile.getTotalLines());
System.out.println("#Parameters/line: " + logfile.getFileHash().get(logfile.getTotalLines()).getFullParameters().length);
System.out.println("Time Stamp in Seconds: " + logfile.getFileHash().get(logfile.getTotalLines()).getTimeStampInSec());
timer = new Timer();
for (int i = 1; i <= logfile.getTotalLines(); i++) {
++currentLine;
t = new Thread(new threadFile(), "logFile_Thread_" + i);
t.start();
}
}
static class threadFile implements Runnable {
public void run() {
timer.schedule(new timedTask(), (long) logfile.getFileHash().get(currentLine).getTimeStampInMilli());
}
}
static class timedTask extends TimerTask {
@Override
public void run() {
// TODO Auto-generated method stub
long nanoTimer = System.nanoTime();
//long milliTimer = System.currentTimeMillis();
System.out.println("systemTime(ns): " + nanoTimer);
}
}
OutPut:
file processing thread started.
Total lines in the file: 3
#Parameters/line: 9
Time Stamp in Seconds: 7.0
systemTime(ns): 4882255697670
systemTime(ns): 4882255928644
systemTime(ns): 4882255985104
Upvotes: 0
Views: 66
Reputation: 34608
I would solve the race on currentLine
differently:
for (int i = 1; i <= logfile.getTotalLines(); i++) {
t = new Thread(new ThreadFile(i), "logFile_Thread_" + i);
t.start();
}
Defining ThreadFile
thus:
static class ThreadFile implements Runnable {
private int lineToProcess;
public ThreadFile( int lineToProcess ) {
super();
this.lineToProcess = lineToProcess;
}
public void run() {
timer.schedule(new timedTask(), (long) logfile.getFileHash().get(lineToProcess).getTimeStampInMilli());
}
}
This way, when you create the runnable, it already knows which line to access, and there is no access to a common variable and no need for synchronization.
There may still be some sort of a problem with logfile
since it, too, is common and not synchronized, but if all we do is read from it and reading does not involve updating its state, it should be OK.
Upvotes: 1
Reputation: 1
I suspect the for-loop and the counter inside it and the way you create a n ew instance of the thread. I would do it that way.
for (int i = 1; i <= logfile.getTotalLines(); i++) {
t = new Thread(threadFile, "logFile_Thread_" + i);
t.start();
}
static Runnable threadFile = new Runnable() {
public void run() {
// TODO Auto-generated method stub
++currentLine;
timer.schedule(new timedTask(), (long)
logfile.getFileHash().get(currentLine).getTimeStampInMilli());
}
};
Because the counter in the for-loop, will get always its maximum value wihch will be applied to all the Timertasks. in other words, if yu have a loop for 5 iterations the counter will get its maximum value depending on how the counter was initalised and then this counter values you use it to parse a specific datat from your file which means you alwas get the value frm the last line then apply it to the timerTask
Upvotes: 1