what is wrong with File.createNewFile()

D

Drazen Gemic

API description says:

Note: this method should not be used for file-locking, as the
resulting protocol cannot be made to work reliably. The FileLock
facility should be used instead.

What does it really mean ?

I am trying to prevent concurrent access by multiple Tomcat
applications running on the same server. That makes FileLock useless.
I'd like to prevent any thread from any accessing resource as long
file exists, no matter which application is particular thread running.
Usual thread synchronization would no work because every application
has classloader of its own.

Will createNewFile() work in this case ? How could it fail ? Is there
a problem with file system cache ?

DG
 
M

Mark Thornton

Drazen said:
API description says:

Note: this method should not be used for file-locking, as the
resulting protocol cannot be made to work reliably. The FileLock
facility should be used instead.

What does it really mean ?

createNewFile is not sufficient for a file locking protocol, you also
need suitable implementations of File.delete and/or File.renameTo as
well (otherwise you can't release the lock). The JavaDoc for both these
methods indicates significant platform differences. Specifically neither
are useful for file locking protocols on Windows.
I am trying to prevent concurrent access by multiple Tomcat
applications running on the same server. That makes FileLock useless.
As of Java 6 the JVM will check if two threads attempt to create
overlapping locks.

Mark Thornton
 
Z

Zig

API description says:

Note: this method should not be used for file-locking, as the
resulting protocol cannot be made to work reliably. The FileLock
facility should be used instead.

What does it really mean ?

I am trying to prevent concurrent access by multiple Tomcat
applications running on the same server. That makes FileLock useless.
I'd like to prevent any thread from any accessing resource as long
file exists, no matter which application is particular thread running.
Usual thread synchronization would no work because every application
has classloader of its own.

Assuming you are running your apps in the same VM (and not attempting to
balance seperate VMs), you should be able to synchronize on an object
initialized via a shared class loader. In theory, you can

synchronized (Object.class) {
...
}

where Object.class should only be loaded once by the system classloader.

Ideally, can you create your own class to add to the shared loader, and
then synchronize on some predefined lock?

Might be a bit cleaner than having to create & cleanup files...

HTH,

-Zig
 
D

Drazen Gemic

Assuming you are running your apps in the same VM (and not attempting to
balance seperate VMs), you should be able to synchronize on an object
initialized via a shared class loader. In theory, you can

There is just one single server and no load balancing.
synchronized (Object.class) {
...

}

where Object.class should only be loaded once by the system classloader.

Ideally, can you create your own class to add to the shared loader, and
then synchronize on some predefined lock?

I guess I could I knew how to do it.

Might be a bit cleaner than having to create & cleanup files...

I'd like a solution like that very much.

DG
 
D

Drazen Gemic

As of Java 6 the JVM will check if two threads attempt to create
overlapping locks.


This is what javase 6 API docs state:

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.

File-lock objects are safe for use by multiple concurrent threads.

I think that it means no chance to lock between multiple threads of
the same JVM.


DG
 
L

Lew

This is what javase 6 API docs state:

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.

File-lock objects are safe for use by multiple concurrent threads.

I think that it means no chance to lock between multiple threads of
the same JVM.

Luckily, Java was designed from the beginning to be able to lock between
multiple threads of the same JVM, by means much more efficient, and way more
reliable, than any file-based method could be.
 
M

Mark Thornton

Drazen said:
This is what javase 6 API docs state:

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.

File-lock objects are safe for use by multiple concurrent threads.

I think that it means no chance to lock between multiple threads of
the same JVM.


DG

My interpretation is that if you lock a file in one thread it will not
prevent access to the file from another thread, but it will prevent
creation of an overlapping lock. However the 'proper' approach is to
create an object which manages the file(s) concerned and which is
visible to all the applications concerned. This may require it to be
loaded in a classloader that precedes those of the applications.

Mark Thornton
 
D

Drazen Gemic

creation of an overlapping lock. However the 'proper' approach is to
create an object which manages the file(s) concerned and which is
visible to all the applications concerned. This may require it to be
loaded in a classloader that precedes those of the applications.

If I could create such object I would not need the files at all.

So far, I know how to access the System Classloader, but I am not sure
if Tomcat is going to let me do that. Then I could load a Class, that
could
be a singleton.

Something like:

ClassLoader scl=ClassLoader.getSystemClassLoader();
Class cl=scl.load("some_package.MutexObject");

'MutexObject' is some class used as synchronization mechanism.
Then I should somehow call static 'getInstance()' method of
the 'MutexObject' class which has some synchronized methods.
I am not quite sure how to do that.

I could, perhaps. call newInstance, and then cast to 'MutexObject',
but how can I prevent multiple instances in different applications
then ?

DG
 
M

Mark Thornton

Drazen said:
If I could create such object I would not need the files at all.

So far, I know how to access the System Classloader, but I am not sure
if Tomcat is going to let me do that. Then I could load a Class, that
could
be a singleton.

Something like:

ClassLoader scl=ClassLoader.getSystemClassLoader();
Class cl=scl.load("some_package.MutexObject");

You don't need to obtain the system class loader, just 'install' the
class files for this object in TomCat's classpath. Class loaders
delegate to their parent and should only load objects which are not
known to the parent class loader. This does mean that this class will be
outside the application(s) and you will need access to the TomCat
configuration.

Another possibility is to host add the mutex to a ServletContext which
is accessible from all applications. ServletContext.setAttribute,
ServletContext.getAttribute might be useful here. Unfortunately there is
some potential for races in initially setting the attribute.
 
L

Lew

Mark said:
Another possibility is to host add the mutex to a ServletContext which
is accessible from all applications. ServletContext.setAttribute,
ServletContext.getAttribute might be useful here. Unfortunately there is
some potential for races in initially setting the attribute.

Static member initializations are guaranteed to 'happen-before' uses of the class.

public class Util
{
private Util() {}

public static final Object LOCK = new Object();
}

public class SomeOther
{
public void method()
{
// ...
synchronized ( Util.LOCK )
{
doSynchWork();
}
// ...
}
}
 
D

Drazen Gemic

You don't need to obtain the system class loader, just 'install' the
class files for this object in TomCat's classpath. Class loaders
delegate to their parent and should only load objects which are not
known to the parent class loader. This does mean that this class will be
outside the application(s) and you will need access to the TomCat
configuration.

I've found a simple solution here:

http://enricogi.blogspot.com/2007/04/singleton-for-tomcat.html

I checked, and it seems to be the same object for all apps. A method
'showTime()'
returns the same value of hash key and creation time. I think that's
it. Many thanks to
everybody who helped me.

package lambdacommon;
//
import java.util.*;
//
public class Mutex {
//
long createdAt;
boolean isLocked;
static Mutex instance=new Mutex();
//
public static Mutex getInstance()
{
return instance;
}
//
private Mutex()
{
isLocked=false;
createdAt=new Date().getTime();
}
//
public synchronized void lock()
{
try {
if(isLocked) wait();
}
catch(InterruptedException ipx) {}
isLocked=true;
}
//
public synchronized void unlock()
{
if(isLocked)
{
isLocked=false;
notify();
}
}
//
public String showTime()
{
return toString() + " created at "+createdAt;
}
}
 
L

Lew

Drazen said:
I've found a simple solution here:

http://enricogi.blogspot.com/2007/04/singleton-for-tomcat.html

I checked, and it seems to be the same object for all apps. A method
'showTime()'
returns the same value of hash key and creation time. I think that's
it. Many thanks to
everybody who helped me.

package lambdacommon;
//
import java.util.*;
//
public class Mutex {
//

// You could go a step further and make 'createdAt' final.
// and instance members generally should be private, although
// package-private isn't so bad

private final
long createdAt
= new Date().getTime();
boolean isLocked;

private
static Mutex instance=new Mutex();
//
public static Mutex getInstance()
{
return instance;
}
//
private Mutex()
{
}
//
public synchronized void lock()
{
try {

// shouldn't this be while instead of if?
 
D

Drazen Gemic

// shouldn't this be while instead of if?

I don't think so. The 'wait()' will wait indefinitely here.
As soon as peer thread unlocks it will call 'notify()', and JVM
will elect one of the waiting threads. If it was 'notifyAll()',
then while is appropriate, because each time all the threads would
compete.

I made a test class. It seems that JVM has some round robin scheme for
waking threads, which suits me fine. Here is the example:

import java.util.*;
//
public class LockedThread extends Thread {
//
String name;
//
public LockedThread(String n)
{
super();
name=n;
}
//
public void run()
{
Mutex m=Mutex.getInstance();
Random r=new Random();
for(;;)
{
System.out.println(name+" at "+ new Date().getTime() + " trying
to lock");
m.lock();
System.out.println(name+" at "+ new Date().getTime() + "
locked");
try { sleep(1000 + r.nextInt(1000)); } catch(Exception ex) { }
m.unlock();
System.out.println(name+" at "+ new Date().getTime() + "
released");
try { sleep(1000 + r.nextInt(1000)); } catch(Exception ex) { }
}
}
//
public static void main(String[] argv)
{
int i;
LockedThread t;
for(i=0; i<10; i++)
{
t=new LockedThread("T"+i);
t.start();
try { sleep(100); } catch(Exception ex) { }
}
try { sleep(30000); } catch(Exception ex) { }
System.exit(0);
}
}

And here is the output, Tx is the thread identifier, big number is the
time, and the rest is status.
Note that Mutex is not in separate package this time. Note that the
order of output lines does not
reflect the order of execution sometimes, that's why the times are
included :

T0 at 1196610235532 trying to lock
T0 at 1196610235532 locked
T1 at 1196610235637 trying to lock
T2 at 1196610235741 trying to lock
T3 at 1196610235849 trying to lock
T4 at 1196610235953 trying to lock
T5 at 1196610236061 trying to lock
T6 at 1196610236169 trying to lock
T7 at 1196610236273 trying to lock
T8 at 1196610236377 trying to lock
T9 at 1196610236482 trying to lock
T0 at 1196610236821 released
T1 at 1196610236821 locked
T0 at 1196610237937 trying to lock
T1 at 1196610238393 released
T2 at 1196610238393 locked
T1 at 1196610239909 trying to lock
T2 at 1196610240369 released
T3 at 1196610240369 locked
T3 at 1196610241397 released
T4 at 1196610241397 locked
T2 at 1196610241933 trying to lock
T4 at 1196610242681 released
T5 at 1196610242681 locked
T3 at 1196610243205 trying to lock
T4 at 1196610243953 trying to lock
T5 at 1196610244469 released
T6 at 1196610244469 locked
T7 at 1196610245973 locked
T6 at 1196610245973 released
T5 at 1196610246401 trying to lock
T6 at 1196610247065 trying to lock
T7 at 1196610247897 released
T8 at 1196610247897 locked
T8 at 1196610248905 released
T9 at 1196610248905 locked
T7 at 1196610249369 trying to lock
T8 at 1196610249985 trying to lock
T9 at 1196610250005 released
T0 at 1196610250005 locked <----- check times here ****
T1 at 1196610251073 locked
T0 at 1196610251073 released
T9 at 1196610251769 trying to lock
T1 at 1196610252169 released
T2 at 1196610252169 locked
T0 at 1196610253017 trying to lock
T2 at 1196610253565 released
T3 at 1196610253565 locked
T1 at 1196610254137 trying to lock
T3 at 1196610254729 released
T4 at 1196610254729 locked
T2 at 1196610255013 trying to lock
T3 at 1196610255789 trying to lock
T4 at 1196610256289 released
T5 at 1196610256289 locked
T4 at 1196610257557 trying to lock
T5 at 1196610257829 released
T6 at 1196610257829 locked
T6 at 1196610259281 released
T7 at 1196610259281 locked
T5 at 1196610259769 trying to lock
T6 at 1196610260369 trying to lock
T7 at 1196610260665 released
T8 at 1196610260665 locked
T7 at 1196610261777 trying to lock
T8 at 1196610262197 released
T9 at 1196610262197 locked
T8 at 1196610263933 trying to lock
T9 at 1196610264201 released
T0 at 1196610264201 locked
T9 at 1196610265725 trying to lock
T0 at 1196610266137 released
T1 at 1196610266137 locked

DG
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,432
Messages
2,571,681
Members
48,796
Latest member
Greg L.

Latest Threads

Top