1

I have two functions which are dealing with the same file:

public MyShelf(){
     …
  //Change the content of note.txt file
  public synchronized void updateFile(){
      File file = getFileUnderPath("PATH\note.txt");
      //Code to update the content of the file
      ...
  }
  //remove note.txt file
  public synchronized void removeFile() throws IOException {
      File file = getFileUnderPath("PATH\note.txt");
      file.delete();
      ...
  }
}

As you see above, there are two functions:

  • updateFile() function changes the content of the file

  • removeFile() function delete the file.

Both functions are dealing with the same file named note.txt

Since there could be multiple threads call either of the above functions, that's why I use synchronized keyword to make my program thread safe.

But I am not sure is my program now really thread safe after using the synchronized keyword? Do I miss something still or is there a better way to make it thread safe ??

Mellon
  • 37,586
  • 78
  • 186
  • 264
  • Synchronize gurantees thread safety and there has to be some reason to feel otherwise in my view. I dont think this question can be answered unless any wrong behaviour is seen with synchronize. – Lokesh Nov 15 '13 at 13:15
  • Synchronize is a perfect way for working in a multi threaded env.. Your question doesn't clarify what is the problem you are facing. – Lokesh Nov 15 '13 at 13:20

7 Answers7

2

Java nio package was designed to allow this.

You can map several regions of one file to different buffers, each buffer can be filled separately by a separate thread.

Prateek
  • 6,785
  • 2
  • 24
  • 37
2

synchronized is the brute force method for thread-safety, but works fine and you are using it correctly. So your code is thread-safe in the terms that it is impossible that 2 threads write and delete the file at the same time.

It is however obviously a problem if one thread first deletes the file, then another one tries to write to it, but this is a logic issue and would require restructuring your code. An easy example would be to add a boolean variable isDeleted that is checked in the write method.

I say brute force because synchronized is not particularly fine grained, it just locks an entire block of code (the method in your case) and prevents access to more than one thread, no matter is some functions inside actually would be thread-safe without a synchronized. Therefore you loose some of the possible execution speed through unnecessary blocking. If you want to apply a more fine-grained synchronization, you however need to develop a much smarter - and therefore error-prone - architecture for your code.

While this is definitely possible using the various tools of the concurrent package, the big question is: how much more speed do you actually gain, and is it worth the extra effort (including debugging)?
In your case the main part of the performance is lost anyway in the file manipulation, which is by nature very slow (compared to CPU operations). So even if you would develop a smart way to reduce locking, the gain in performance would be negligible, and most likely not worth the time and effort.

In short: Yes, you doing it right, but need to consider something to prevent write into a deleted file.

TwoThe
  • 13,879
  • 6
  • 30
  • 54
1

It is thread safe as it is yes. Synchronized on a method basically uses the instance as a lock for the whole block of the method: no two threads will be able to call a synchronized method on the same instance.

However, if you have 2 instances of MyShelf with a hard coded file path then potentially thread A could call update on instance 1, and thread B could call remove on instance 2.

vptheron
  • 7,426
  • 25
  • 34
  • So, if MyShelf is a singleton, then, synchronize on method is quite thread safe, right? – Mellon Nov 15 '13 at 13:27
  • Yes, either make sure that you only create one instance of MyShelf, or make your methods static so that the class itself is used as a lock. – vptheron Nov 15 '13 at 13:39
1

Because "Each action in a thread happens-before every action in that thread that comes later in the program's order," one approach would be to let updateFile() invoke delete() when it is finished updating the file.

Alternatively, let updateFile() add the completed file to a suitable implementation of BlockingQueue where another waiting thread can safely delete() it.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
0

Could try something like:

public MyShelf(){
     …
  Object theLock = new Object();
  //Change the content of note.txt file
  public void updateFile(){
      synchronized (theLock) {
         File file = getFileUnderPath("PATH\note.txt");
         //Code to update the content of the file
         ...
      }
  }
  //remove note.txt file
  public void removeFile() throws IOException {
    synchronized (theLock) {
      File file = getFileUnderPath("PATH\note.txt");
      file.delete();
      ...
    }
  }
}
AppX
  • 528
  • 2
  • 12
  • Do you mean it is better than using synchronized keyword? I am not seeking for an alternative way of doing things, but a better way & it's better to also point out why it is better than synchronized keyword, that's my point to post the question. Thanks. – Mellon Nov 15 '13 at 13:15
  • by synchronizing on a method, only one thread may execute the method at a time. Synchronizing on the object prevents anyone from updating a file while someone deletes it. – AppX Nov 15 '13 at 13:18
  • This code is strictly equivalent to putting synchronized on both methods. – vptheron Nov 15 '13 at 13:25
  • @AppX using `synchronized` is **not** blocking on a method, it blocks using the instance (this) as lock. So it will have the same result as yours code. If you change your lock Object to `static` (and `final`) then it would be different and better IMO - no matter how many instances of `MyShelf` were created/used, only one could run. – user85421 Nov 15 '13 at 13:39
  • There is no explanation on why this should be better (which it isn't), telling me that you only quote what others say, without even knowing why. – TwoThe Nov 16 '13 at 11:17
0

A better way to synchronize this is to use a file lock: How can I lock a file using java (if possible).

Different instances of MyShelf are not synchronized with each other, so if you have two instances of MyShelf for the same file, they might be updating this file simultaneously.

Another option is to introduce a file manager and make sure that direct file access is not used in your app. However, this won't not save you from a case when two instances of your app are running simultaneously.

Community
  • 1
  • 1
Andrey Chaschev
  • 16,160
  • 5
  • 51
  • 68
-1

No, it's not safe.

synchronized means only one thread will enter into a particular function. But there is a possibilty that one thread is exceuting updateFile() and other is doing removeFile(), then exception will be thrown by the JVM.

So, for avoiding this, put one boolean variable and toggle it when some thread enters into the function.

Andrei Nicusan
  • 4,555
  • 1
  • 23
  • 36
SeeTheC
  • 1,560
  • 12
  • 14