4

I recently added filelocks to my downloader asynctask:

FileOutputStream file = new FileOutputStream(_outFile);
file.getChannel().lock();

and after download completes, file.close() to release lock.

From a called BroadcastReceiver (different thread), I need to go through the files and see which are downloaded and which are still locked. I started with trylock:

for (int i=0; i<files.length; i++) {
    try {
        System.out.print((files[i]).getName());
        test = new FileOutputStream(files[i]);
        FileLock lock = test.getChannel().tryLock();
        if (lock != null) {
            lock.release();
            //Not a partial download. Do stuff.
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        test.close();
    }
}

Unfortunately I read the file is truncated (0 bytes) when the FileOutputStream is created. I set it to append, but the lock doesn't seem to take effect, all appear to be un-locked (fully downloaded)

Is there another way to check if a write-lock is applied to the file currently, or am I using the wrong methods here? Also, is there a way to debug file-locks, from the ADB terminal or Eclipse?

NoBugs
  • 9,310
  • 13
  • 80
  • 146

2 Answers2

2

My first thought would be to open it for append per the javadocs

test = new FileOutputStream(files[i], true); // the true specifies for append
RHSeeger
  • 16,034
  • 7
  • 51
  • 41
  • Nice, now it doesn't delete the file, but it doesn't seem to recognize the lock. All files appear to be un-locked. – NoBugs Oct 04 '12 at 04:46
  • 1
    You may be running into the problem described by EJP. If the lock is held per process, then you may be able to claim the lock on it even if is already locked by another thread in your process. Unfortunately, I don't have an answer to that part. – RHSeeger Oct 04 '12 at 05:01
2

None of this is going to work. Check the Javadoc. Locks are held on behalf of the entire process, i.e. the JVM, not by individual threads.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • 1
    I don't understand, I *want* to hold locks on behalf of my app's process. – NoBugs Oct 04 '12 at 03:14
  • Not sure why a thread would want to lock only for itself, but that seems to be what it's doing. Do you know a better method for marking a file as in-use? – NoBugs Oct 04 '12 at 05:09
  • @NoBugs No you don't, you want thread A to hold a lock and thread B to fail to obtain a lock until thread A releases it. The point is that tryLock() will always succeed because the process as a whole already has the lock. Your code relies on it failing, i.e. returning null. – user207421 Oct 04 '12 at 06:10
  • I didn't downvote, I think you may be right on this, but your answer didn't include that explanation that a Java process can't look for its own locks. It also doesn't tell what might be used instead. – NoBugs Oct 04 '12 at 14:30
  • 1
    @NoBugs It follows directly from what I did state, and it's in the [Javadoc](http://docs.oracle.com/javase/6/docs/api/java/nio/channels/FileChannel.html#tryLock()) I referred you to. "If it fails to acquire a lock because an overlapping lock is held by *another program* then it returns null" [my emphasis]. No doubt about it. – user207421 Oct 05 '12 at 01:52
  • You're right, I hadn't read that part of the documentation: "File locks are held on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine." So, these Filelocks are held for a certain JVM (App, for Android?) and can only be seen by others. – NoBugs Oct 05 '12 at 02:31
  • Sometimes simple one is the solution, instead of a lock I created a blank file with similar name, 'marking' the file as in-progress. – NoBugs Oct 06 '12 at 06:47
  • @NoBugs I would have used synchronization myself. Much more reliable. – user207421 Apr 01 '15 at 23:16
  • Doesn't synchronized lock and unlock based on an *object* - `synchronized(new File(...))` wouldn't do anything in that case? – NoBugs Apr 02 '15 at 02:19