2

I've written a Java class that implements a "lock file" to prevent a period job from running more than once concurrently. It's based upon java.nio.channels.FileChannel.tryLock and works quite well.

My class allows client code to supply a timeout value indicating how long it's willing to wait for the lock file to become available, and if a timeout occurs, I'm throwing an IOException. This also works quite well.

But I'm wondering if there is a better exception type to be using, since IOException is fairly generic. Client code catching an IOException wouldn't be able to know if the problem was due to e.g. the timeout itself or some other issue with the filesystem, etc. (unless that other issue throws a subclass of IOException of course).

Briefly leafing through the Java API, I see some candidates but I don't really like any of them for various reasons:

  1. java.util.concurrent.TimeoutException (this isn't really a "concurrent" usage)
  2. java.nio.channels.FileLockInterruptionException (docs indicate a very specific reason for this exception; doesn't match my case)
  3. java.nio.channels.InterruptedByTimeoutException (similar reasons to above)

Any suggestions?

I'd prefer something that is available back to Java 7 if possible.

EDIT

Obviously, a custom exception class is possible, but I was wondering if there was something in the standard API that would be appropriate.

Christopher Schultz
  • 20,221
  • 9
  • 60
  • 77
  • Whatever you should use should be a subtype of `IOException`. – chrylis -cautiouslyoptimistic- Dec 09 '16 at 22:35
  • I'd say it's pretty much in the concurrency domain. – ZhongYu Dec 09 '16 at 22:36
  • 1
    You say: *implements a "lock file" to prevent a period job from running more than once concurrently*, and later you say: *this isn't really a "concurrent" usage*. It is: one thread holds the lock and another thread tries to get it. It's definitely a concurrency issue. BTW, the fact you're using a file lock to deal with this concurrency issue looks like an implementation detail to me, so I wouldn't use an IOException. – JB Nizet Dec 09 '16 at 22:37
  • @JBNizet I say "not concurrent" because the java.util.concurrent API deals with thread-safety in "Java land" and I feel like this use-case falls outside of that. My lock file provides protection across process boundaries as well, so I feel like the scope is sufficiently different that using a class from Java's concurrent package might be confusing. – Christopher Schultz Dec 09 '16 at 22:49
  • @JBNizet As for the "implementation detail" issue, the class is designed and documented to use an on-disk file as a locking mechanism. So while it definitely *is* an implementation detail, it's the definition of the implementation, interface, etc. so I think `IOException` is at least not *in*appropriate. – Christopher Schultz Dec 09 '16 at 22:51

3 Answers3

2

I think that java.util.concurrent.TimeoutException is appropriate. The javadoc says:

"Exception thrown when a blocking operation times out. Blocking operations for which a timeout is specified need a means to indicate that the timeout has occurred."

Your method that is calling trylock is a blocking operation in the sense that is envisaged by the authors.

You say: "this isn't really a "concurrent" usage" ... but that depends on your perspective. You are using a Lock API, and that interface is declared within the java.util.concurrent package tree. And presumably you are designing your API so that it can easily be used in a concurrent application. (And if not ... why not?)


IMO, the only good argument for using IOException or an existing or custom subclass of IOException would be if the client operation is modeled as an I/O operation. For instance, if the API uses I/O exceptions to signal other things.

Another argument against using IOException is that it is too general. It says the the caller of your API method(s) "you need to be prepared for any IOException". That includes all sorts of exceptions that your current implementation won't throw, but a future one might.


The other alternative is to declare your own custom exception class that is not a subclass of IOException. On the face of it, that appears better than an I/O exception.


As for the "implementation detail" issue, the class is designed and documented to use an on-disk file as a locking mechanism. So while it definitely is an implementation detail, it's the definition of the implementation, interface, etc. so I think IOException is at least not inappropriate.

I would argue that it is a bad idea to specify an API like that. Suppose that you decide later on that another kind of locking might be more appropriate. If you have specified the locking details in the interface, you can't change them. Or at least, not without "rewriting the contract" in a way that could break an existing client of the API.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • I disagree with some of the specifics, but I like the justification. Thanks for your thoughts. I'm likely to actually create a new subclass of `TimeoutException` and also throw `IOException` because that can happen as well and needs to be signaled to the caller, separately. – Christopher Schultz Dec 13 '16 at 19:40
1

Create a custom exception class that extends IOException. This allows the client to either handle the specific exception if it wants to, or as a generic IOException along with all the other reasons that things might fail.

Easy for you to implement. Easy for the caller to use.

Rob
  • 6,247
  • 2
  • 25
  • 33
0

JDK contains lots of variants of timeout Exceptions like SQLTimeoutException, SocketTimeoutException, etc.., but unfortunately, there is no parent class such as TimeoutException which can be extended or generally used across for all Timeout exceptions.

So, you can write a custom Exception and use it, as shown below:

public class FileTimeoutException extends IOException {

    private String message;

     public FileTimeoutException(String message) {
           this.message= message;
     }
    //add the other required methods
}
Vasu
  • 21,832
  • 11
  • 51
  • 67