how to notify to another thread about a file being modified - java

I am new to the java multithreading programming. I know that it can be done by thread communication but i don't know how to proceed. I don't know how one thread would notify another if some changes are done in a file. The problem is mentioned below.
I have a comma separated file in which some lines are written. I want two threads to be started from my main thread. The csv file might be appended externally/manually. One of the thread will notify second thread if some changes are done in csv file and second thread will read that file concurrently line by line and perform some task.
Thanks.

You can use java.nio.file.WatchService for this purpose.
Refer Tutorial
From the link:-
The Watch Service API is designed for applications that need to be
notified about file change events. It is well suited for any
application, like an editor or IDE, that potentially has many open
files and needs to ensure that the files are synchronized with the
file system. It is also well suited for an application server that
watches a directory, perhaps waiting for .jsp or .jar files to drop,
in order to deploy them.

You create two thread, that inside their run method, they both use one Object as the thread wait and notify signal.
The first thread (T1), would synchronize on the object and wait on it.
The second thread (T2), would synchronize on the object, do something with it, and signal a notify.
The following snippets should give you idea... (please disregard about the endless loop and bad exception handling, its just to express the idea for ease of understanding).
public class IdeaOfThreadingWithWaitAndNotify {
public static void main(String[] args) {
File f = new File("grow.txt");
if(!f.exists()) {
try {
f.createNewFile();
Thread appenderThread = new Thread(new FileAppender(f));
Thread checkerThread = new Thread(new FileSizeCounter(f));
appenderThread.start();
checkerThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static class FileAppender implements Runnable {
private File file;
private FileOutputStream fos;
public FileAppender(File file) throws FileNotFoundException {
super();
this.file = file;
fos = new FileOutputStream(file);
}
public void run() {
while(true) {
synchronized (file) {
try {
fos.write("Appended... ".getBytes());
fos.flush();
file.notify();
Thread.sleep(1000);
} catch (IOException e) {
} catch (InterruptedException e) {
}
}
}
}
}
public static class FileSizeCounter implements Runnable {
private File file;
public FileSizeCounter(File file) {
super();
this.file = file;
}
public void run() {
while(true) {
synchronized (file) {
try {
file.wait();
} catch (InterruptedException e) {
}
System.out.println("File changed .. now size is " + file.length());
// you can do other stuff with the file...
}
}
}
}
}
there you can see, between the two thread, they are sharing the same "file" instance and use it as the wait and notify signaling. Object who call the wait will have its execution flow stop right there, until the other thread call a notify on it. Then the waiting thread can continue.
I hope this helps.

Related

Single program instance

I need to make a program, which can be executed in single instance. I tried to create a temporary file and delete it before exit program.
public static boolean isLocked() {
File f = new File("lock.txt");
return f.exists();
}
public static void lock() {
String fname = "lock.txt";
File f = new File(fname);
try {
f.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void unlock() {
File f = new File("lock.txt");
f.delete();
}
In frame
private void initialize() {
lock();
}
private void setFrameHandler() {
frame.addWindowListener(new java.awt.event.WindowAdapter() {
#Override
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
unlock();
}
});
}
Problem occurs if program is finished with emergency (e.g. electricity cuts). File does not remove, and running a new instance is impossible.
How to make a reliable single-instance verification?
You could check for another instance of the program at startup using the GetProcesses method as described here
But that only works depending on the scenario you have (might not see all processes of other users)
Another thing you could do is simply checking, if a specific file is locked via File.Open
File.Open ("path.lock", FileMode.OpenOrCreate, FileAccess.ReadWrite);
As long as you keep the resulting FileStream open in your program no other program can open the file in that mode either. This is basically how Unix lock files work too. Of course you have to catch an IOException (hinting you to a locked file).
Disclaimer: I did not try that code out so please check if I gave you the right parameters.
Edit: You could also check out this Code-Project article on how to do it with the win32 API
Another attempt using windows messaging has been done here
A simple approach to this on a single machine is to write a 'PID file', which is literally a file containing the operating system's ID of the process currently running. You create this when you start your "critical" work, and remove it on successful completion.
Since it is unlikely that the process would be started again with the same PID, you can simply check to see if the PID file already exists, and if so, if that process is still running.

race condition with file getAbsolutePath() java

It seems like I have a race condition when I call file.getAbsolutePath() in my Java program.
In one thread I am processing a file and when it is finished processing I am changing the filename and moving it to another directory on the UNIX file system.
In a separate thread running in parallel I am attempting to open this file that is being processed and reading its contents. In 99% of use cases this operation is fine however I have noticed sometimes that the operation fails with a FileNotFound exception.
When I catch this exception I am logging the file.getAbsolutePath() value and I see the value is the concatenation of the path of the file in the processed directory it has been moved to and also the path of the file in the directory it was present in before processing completed.
Has anyone experienced a similar problem in the past and how did you get around it?
Thanks
It seems you need to synchronize the file access from separate threads using a class that does this, let's call it FileManager.
First option in implementing the FileManager is to use an exclusive lock. For example:
class FileManager {
private Object lock = new Object();
public void processFile() {
synchronized(lock) {
...
}
}
public void readFile() {
synchronized(lock) {
...
}
}
}
If there are many more readers than writers a Read/Write Lock is more suitable as it allows multiple concurrent readers but only a single writer:
class FileManager {
private final Lock readLock;
private final Lock writeLock;
FileManager() {
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(false);
readLock = readWriteLock.readLock();
writeLock = readWriteLock.writeLock();
}
public void processFile() {
writeLock.lock();
try {
...
}
finally {
writeLock.unlock();
}
}
public void readFile() {
readLock.lock();
try {
...
}
finally {
readLock.unlock();
}
}
}

Synchronisation on java.io.File Object

Is it good to use synchronised on java.io.File Object. When you want to alternatively read and write that File Object using two threads: one for reading and one for writing.
public class PrintChar {
File fileObj;
public void read() {
while (true) {
synchronized (this) {
readFile();
notifyAll();
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()
+ " throws Exception");
e.printStackTrace();
}
}
}
}
public void write(String temp) {
while (true) {
synchronized (this) {
writeFile(temp);
notifyAll();
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()
+ " throws Exception");
e.printStackTrace();
}
}
}
}
public void setFileObj(File fileObj) {
this.fileObj = fileObj;
}
public void readFile() {
InputStream inputStream;
try {
inputStream = new FileInputStream(fileObj);
// Get the object of DataInputStream
DataInputStream in = new DataInputStream(inputStream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
// Read File Line By Line
while ((strLine = br.readLine()) != null) {
// Print the content on the console
System.out.println(strLine);
}
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void writeFile(String temp) {
BufferedWriter bw;
try {
bw = new BufferedWriter(new FileWriter(fileObj, true));
bw.write(temp);
bw.newLine();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
final PrintChar p = new PrintChar();
p.setFileObj(new File("C:\\sunny.txt"));
Thread readingThread = new Thread(new Runnable() {
#Override
public void run() {
p.read();
}
});
Thread writingThread = new Thread(new Runnable() {
#Override
public void run() {
p.write("hello");
}
});
Thread Randomizer = new Thread(new Runnable() {
#Override
public void run() {
while (true)
try {
Thread.sleep(500000);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()
+ " throws Exception");
e.printStackTrace();
}
}
});
readingThread.start();
writingThread.start();
Randomizer.start();
}
}
In the code above I have used Synchronised(this), Can i use Synchronise(fileObj)??
One More solution I have got from one of my professors is to encapsulate the read and write in objects and push them in a fifo after every operation, if anybody elaborate on this
Edit:
Now that you have added your code, you can lock on fileObj but only if it is not changed. I would move it to the constructor and make it final to make sure that someone doesn't call setFileObj inappropriately. Either that or throw an exception if this.fileObj is not null.
Couple other comments:
Don't use notifyAll() unless you really need to notify multiple threads.
If you catch InterruptedException, I'd quit the thread instead of looping. Always make good decisions around catching InterruptedException and don't just print and loop.
Your in.close(); should be in a finally block.
You can lock on any object you want as long as both threads are locking on the same constant object. It is typical to use a private final object for example:
private final File sharedFile = new File(...);
// reader
synchronized (sharedFile) {
// read from file
}
...
// writer
synchronized (sharedFile) {
// write to file
}
What you can't do is lock on two different File objects, even if they both point to the same file. The following will not work for example:
private static final String SHARED_FILE_NAME = "/tmp/some-file";
// reader
File readFile = new File(SHARED_FILE_NAME);
synchronized (readFile) {
...
}
// writer
File writeFile = new File(SHARED_FILE_NAME);
synchronized (writeFile) {
...
}
Also, just because you are locking on the same File object does not mean that the reading and writing code will work between the threads. You will need to make sure that in the writer that all updates are flushed in the synchronized block. In the reader you probably do not want to use buffered streams otherwise you will have stale data.
In general, locking across I/O is not a great idea. It's better to construct your program such that you guarantee by design that usually a given section of the file is not being concurrently written and read, and only lock if you absolutely must mediate between reads and writes of a given piece of the file.
Usually not. There are much better ways: Use a ReentrantLock
This class already offers the "lock for reading/writing" metaphor. It also correctly handles the case that many threads can read at the same time but only one thread can write.
As other people already mentioned, locking will only work if all threads use the same File instance.
Make sure you flush the output buffers after each write; this will cost some performance but otherwise, you'll get stale reads (read thread won't find data that you expect to be there).
If you want to simplify the code, add a third thread which accepts commands from the other two. The commands are READ and WRITE. Put the commands in a queue and let the 3rd thread wait for entries in the queue. Each command should have a callback method (like success()) which the 3rd thread will call when the command has been executed.
This way, you don't need any locking at all. The code for each thread will be much more simple and easy to test.
[EDIT] Answer based on your code: It would work in your case because everyone uses the same instance of fileObj but it would mix several things into one field. People reading your code would expect the file object to be just the path to the file to read. So the solution would violate the principle of least astonishment.
If you'd argue that it would save memory, then I'd reply with "premature optimization".
Try to find a solution which clearly communicates your intent. "Clever" coding is good for your ego but that's about the only positive thing that one can say about it (and it's not good for your ego to learn what people will say about you after they see your "clever" code for the first time...) ;-)
Queueing off read/write objects to one thread that then performs the operation is a valid approach to something, but I'm not sure what.
Wha it would not do, for example, is to enforce read/write/read/write order as you specified in your earlier question. There is nothing to stop the read thread queueing up 100 read requests.
That could be prevented by making the thread that submits an object wait on it until it is signaled by the read/write thread, but this seems a very complex way of just enforcing read/write order, (assuming that's what you still want).
I'm getting to the state now where I'm not sure what it is you need/want.

Implementation problems with ThreadPoolExecutor

I am using multiple threads to upload files to the server. The Java Applet is responsible for displaying the UI. Initially I start 5 threads using ThreadPoolExecutor & assign 5 files to them . After each upload, I get a notification from the server. When a thread completes execution , another new thread is assigned with a file until all the files are uploaded to the server.
Basic code structure as follows:
i> a method startUpload() is being called from the Java Applet which is responsible for handling the upload functionality.
class Upload extends Runnable{
...............................
..............................
public void startUpload() {
............................... //other initialisations done
int waitTime = 500;
Random random = new Random();
ExecutorService executor = new ThreadPoolExecutor(5, 5, 50000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(300));
while (it.hasNext()) {
int time = random.nextInt(1000);
waitTime += time;
newFile = new File((String) it.next());
executor.execute(new Runnable() {
#Override
public void run() {
try{
Thread.sleep(wait);
}
catch(Exception e){
}
processFile1(newFile);
}
});
}
try {
Thread.sleep(waitTime);
executor.shutdown();
executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);
} catch (Exception e) {
}
}
}
The problem I am facing currently.
i> The UI is only updating at the end when all the files are upload. In the intermediate stage the UI is in a hanged state. It seems like the EDT is going to a blocked state.
The same code for UI rendering was working fine when I was using Thread class , notify/ sleep to implement the same functionality . I changed the code to ThreadPoolExecutor since I saw in a no of blogs/articles that its a better way of implementing multithreading from Java ver 5.0.
ii> Another thing which I noticed with the ThreadPoolExecutor , when I am uploading multiple files with size 1KB (for testing purpose) , if I remove all the wait() from the above code , the following line assigns a new file but the the same file is always being uploaded everytime by the multiple threads.
newFile = new File((String) it.next());
But on adding sleep() withing the run() , the multiple threads upload different files to the server.
Is there any implementation issue with the above code ?
Problem 1: newFile is a (static?) field instead of a local variable.
What you want is to make sure that the local capture of newFile is different each loop. As such, it should look more like:
while(it.hasNext()) {
final File newFile = new File((String) it.next());
executor.execute(new Runnable() {
#Override
public void run() {
processFile1(newFile); // Local only to this iteration of the loop.
}
}
}
Your code is all wrapped in a Runnable instance. Can you let us know what Thread this is called from? If it's on the EDT then that would explain why the UI locks up.
A small issue is the lack of generics on your iterator. In theory, you should be iterating over a collection of Strings:
Collection<String> listOfFiles = ...
Iterator<String> it = listOfFiles.iterator();
while(it.hasNext()) {
String filename = it.next(); // No cast necessary
}
The UI is hanging because you are blocking the EDT thread. This code is the culprit:
try {
Thread.sleep(waitTime);
executor.shutdown();
executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);
} catch (Exception e) {
}
The idea of an ExecutorService is that you create it one time during initialization and never shut it down until the program is ready to exit. An idiom for this might be:
ExecutorService executor = Executors.newFixedThreadPool(5);
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
executor.shutdown();
}
});
As #Bringer128 mentioned, the second problem is caused by the fact that you are changing the value of a static or member variable and not assigning the File reference to a new location. If the code were correct, we would expect to see the newFile declared as final File newFile because non-final local variables may not be referenced in an inner-class.

Java threads problem

I have a problem with java threads:
public class MyClass{
public void Core(){
runTools(); //here I would like to call runTools() method
}
public void runTools(){
final String run_tool ="cmd.exe /C sources.exe";
Runnable doRun = new Runnable() {
public void run() {
try {
Process tool_proc = Runtime.getRuntime().exec(run_tool);
}
catch (IOException e) {
e.printStackTrace();
}
}
};
Thread th = new Thread(doRun);
th.start();
}
}
If I do this, then I don't know why, but the thread doesn't work. Please give me some ideas to create a thread. I have already been seen lots of examples, but I should some code such as my example here. Thanks!
At first, if you just want to execute an external command and do not bother about its output*, then using a dedicated thread is unnecessary, since the process itself will already run in parallel to your application, so the exec() call will not really hang your programm.
Nevertheless your code looks correct to me. You should check the working directory of your application (maybe cmd.exe cannot find your sources.exe) and evaluate the output the process you start gives you, by directing the streams of tool_proc.getErrorStream() and tool_proc.getInputStream() to System.out or logging them.
EDIT:
* The Java documentation states you always should read the InputStreams of your processes as failing to do so might result in filling up a system buffer, which will eventually hang the process.
problem 1 You create object for Runnable Interface,that is never possible.
Runnable *obj=new Runnable(); // this is not correct
problem 2 You write definition for Run() method with in the another method runTools()
we can create object for a class that implements The Runnable interface.
Due to these your code is not working.
Try the fallowing way
public class MyClassName1 implements Runnable
{
public void start()
{
//here you can call your method:runTools()
runTool();
}
}
public void runTools()
{
final String run_tool ="cmd.exe /C sources.exe";
try
{
Process tool_proc = Runtime.getRuntime().exec(run_tool);
}
catch (IOException e)
{
e.printStackTrace();
}
}
here is my main class of the programe
public class MyClassName2
{
public static void main(String[] ars)
{
Runnable *obj1=new MyClassName1();
Thread t=new Thread(obj);
t.start()
}
I hope this helps to you

Categories