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();
}
}
}
Related
A server project, might run for very long time and create many threads.
In the following code I ask myself do i have to protect the lock somehow in addition to an overall try catch in method setData(MyData data):
note: assuming its thread-safe, i am not really familiar with other reasons or natural disasters that may cause thread termination, like windows 7 limitations or so. (i am not greedy, using +-5 threads, but still)
public class MyFactory {
private ReadWriteLock rwl = new ReentrantReadWriteLock();
private Lock readLock = rwl.readLock();
private Lock writeLock = rwl.writeLock();
private static MyFactory _instance = new MyFactory();
private static Map<Integer, MyData> mapDatas = new HashMap<>();
public static MyFactory getInstance() {
return _instance;
}
public void setData(MyData data) {
writeLock.lock();
try {
mapData.put(...);
} catch (Exception exc) {
...
} finally {
writeLock.unlock();
}
}
Assuming that you never expose the lock to other objects and you always use unlock the lock in a finally block, you are fine.
The reason is that the code in the finally block is always called if something happens in the try or catch blocks. Even if an Error is thrown this is true. These happen for example when you're out of memory or there is a linkage error with some DLL. If something worse happens than an Error, that will likely also end your process and make the problem moot.
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.
We need to lock a method responsible for loading database date into a HashMap based cache.
A possible situation is that a second thread tries to access the method while the first method is still loading cache.
We consider the second thread's effort in this case to be superfluous. We would therefore like to have that second thread wait until the first thread is finished, and then return (without loading the cache again).
What I have works, but it seems quite inelegant. Are there better solutions?
private static final ReentrantLock cacheLock = new ReentrantLock();
private void loadCachemap() {
if (cacheLock.tryLock()) {
try {
this.cachemap = retrieveParamCacheMap();
} finally {
cacheLock.unlock();
}
} else {
try {
cacheLock.lock(); // wait until thread doing the load is finished
} finally {
try {
cacheLock.unlock();
} catch (IllegalMonitorStateException e) {
logger.error("loadCachemap() finally {}",e);
}
}
}
}
I prefer a more resilient approach using read locks AND write locks. Something like:
private static final ReadWriteLock cacheLock = new ReentrantReadWriteLock();
private static final Lock cacheReadLock = cacheLock.readLock();
private static final Lock cacheWriteLock = cacheLock.writeLock();
private void loadCache() throws Exception {
// Expiry.
while (storeCache.expired(CachePill)) {
/**
* Allow only one in - all others will wait for 5 seconds before checking again.
*
* Eventually the one that got in will finish loading, refresh the Cache pill and let all the waiting ones out.
*
* Also waits until all read locks have been released - not sure if that might cause problems under busy conditions.
*/
if (cacheWriteLock.tryLock(5, TimeUnit.SECONDS)) {
try {
// Got a lock! Start the rebuild if still out of date.
if (storeCache.expired(CachePill)) {
rebuildCache();
}
} finally {
cacheWriteLock.unlock();
}
}
}
}
Note that the storeCache.expired(CachePill) detects a stale cache which may be more than you are wanting but the concept here is the same, establish a write lock before updating the cache which will deny all read attempts until the rebuild is done. Also, manage multiple attempts at write in a loop of some sort or just drop out and let the read lock wait for access.
A read from the cache now looks like this:
public Object load(String id) throws Exception {
Store store = null;
// Make sure cache is fresh.
loadCache();
try {
// Establish a read lock so we do not attempt a read while teh cache is being updated.
cacheReadLock.lock();
store = storeCache.get(storeId);
} finally {
// Make sure the lock is cleared.
cacheReadLock.unlock();
}
return store;
}
The primary benefit of this form is that read access does not block other read access but everything stops cleanly during a rebuild - even other rebuilds.
You didn't say how complicated your structure is and how much concurrency / congestion you need. There are many ways to address your need.
If your data is simple, use a ConcurrentHashMap or similar to hold your data. Then just read and write in threads regardlessly.
Another alternative is to use actor model and put read/write on the same queue.
If all you need is to fill a read-only map which is initialized from database once requested, you could use any form of double-check locking which may be implemented in a number of ways. The easiest variant would be the following:
private volatile Map<T, V> cacheMap;
public void loadCacheMap() {
if (cacheMap == null) {
synchronized (this) {
if (cacheMap == null) {
cacheMap = retrieveParamCacheMap();
}
}
}
}
But I would personally prefer to avoid any form of synchronization here and just make sure that the initialization is done before any other thread can access it (for example in a form of init method in a DI container). In this case you would even avoid overhead of volatile.
EDIT: The answer works only when initial load is expected. In case of multiple updates, you could try to replace the tryLock by some other form of test and test-and-set, for example using something like this:
private final AtomicReference<CountDownLatch> sync =
new AtomicReference<>(new CountDownLatch(0));
private void loadCacheMap() {
CountDownLatch oldSync = sync.get();
if (oldSync.getCount() == 0) { // if nobody updating now
CountDownLatch newSync = new CountDownLatch(1);
if (sync.compareAndSet(oldSync, newSync)) {
cacheMap = retrieveParamCacheMap();
newSync.countDown();
return;
}
}
sync.get().await();
}
I was creating an application in Java for which I want only one instance running. For this purpose I created a file and got a lock while my application is running.
I have following code which works on Windows, but failed on Linux: once I acquire a lock without unlocking it I can get another lock on it.
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
public class MyApp {
private static File f;
private static FileChannel channel;
private static FileLock lock;
public static void main(String[] args) {
try {
f = new File("RingOnRequest.lock");
// Check if the lock exist
if (f.exists()) {
// if exist try to delete it
f.delete();
}
// Try to get the lock
channel = new RandomAccessFile(f, "rw").getChannel();
lock = channel.tryLock();
if(lock == null)
{
// File is lock by other application
channel.close();
throw new RuntimeException("Only 1 instance of MyApp can run.");
}
// Add shutdown hook to release lock when application shutdown
ShutdownHook shutdownHook = new ShutdownHook();
Runtime.getRuntime().addShutdownHook(shutdownHook);
//Your application tasks here..
System.out.println("Running");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
catch(IOException e)
{
throw new RuntimeException("Could not start process.", e);
}
}
public static void unlockFile() {
// release and delete file lock
try {
if(lock != null) {
lock.release();
channel.close();
f.delete();
}
} catch(IOException e) {
e.printStackTrace();
}
}
static class ShutdownHook extends Thread {
public void run() {
unlockFile();
}
}
}
You are deleting the lock file every time you run, so only one process can have a lock on it.
When you use FileLock, it is purely advisory—acquiring a lock on a file may not stop you from doing anything…reading, writing, and deleting a file may all be possible even when another process has acquired a lock. Sometimes, a lock might do more than this on a particular platform, but this behavior is unspecified, and relying on more than is guaranteed in the class documentation is a recipe for failure.
An "advisory lock" is only a signal that is visible to other processes that bother to look for it. If you depend on it for more than that, your program will break when run on some other platform.
Why would you delete the lock file anyway? The lock file is just like a boolean flag that is visible to every process on the system. Design your protocol to use it that way, and you'll have a reliable, cross platform locking mechanism.
Why don't you save the PID into a file, and instead of locking the file, verify if there's a process with that ID. If there is, and it's an instance of your application, you know it's already running.
A socket might be a good idea as well, since you can use it to communicate to the running instance something.
EDIT:
Also, from FileLock's javadoc:
Whether or not a lock actually prevents another program from accessing
the content of the locked region is system-dependent and therefore
unspecified.
Use mkdir. On unix systems this is an atomic operation – it will succeed if a new directory is successfully created, otherwise it will fail.
Example:
File lockFile = new File("/path/to/lockdir");
boolean hasLock = lockFile.mkdir();
if (!hasLock) {
throw new IOException("could not get lock");
}
// do stuff
lockFile.delete();
I used same sample as you and got same problem on Mac OS X. It seems that file lock does not prevent file deletion on POSIX systems . Your app wil still have some kind of handle to that file until you unlock it. So consider using lock file with PID in it's name( or inside file).
I tested it on both Windows and Linux. Works fine. The lock file gets deleted automatically when the application closes normally. So you don't have to worry about the lock file staying there when you restart the application. Just comment out the following lines:
if (f.exists()) {
// if exist try to delete it
f.delete();
}
However, you may want to consider what happens if your application crashes and does not close in a normal fashion.
Recently i encountered the same kind of problem, but in my case i had an advantage: my application polled some directory only after some timeout. As my application did not immediately poll for directory i wrote special class that creates lock file with his own PID inside in init method, after that before it tries to work with directory it needs to call ownedLock() - if it returns true then we can work otherwise exit(code is in Kotlin but you will get the main idea):
import java.io.File
import java.lang.management.ManagementFactory
class DirectoryLocker(private val directory: String, private val lockName: String) {
private val lockFile by lazy { File("$directory/$lockName.lock") }
// Will try to acquire lock to directory, whoever last writes its pid to file owns the directory
fun acquireLock() = with(lockFile) {
createNewFile()
writeText(currentPID())
}
fun ownedLock(): Boolean = lockFilePid() == currentPID()
fun releaseOwnedLock() {
if(lockFilePid() == currentPID()) lockFile.delete()
}
private fun currentPID(): String {
val processName = ManagementFactory.getRuntimeMXBean().name
return processName.split("#".toRegex()).first()
}
private fun lockFilePid(): String? {
return if(lockFile.exists()) lockFile.readLines().first() else null
}
}
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.