Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / December 2007

Tip: Looking for answers? Try searching our database.

what is wrong with File.createNewFile()

Thread view: 
Drazen Gemic - 01 Dec 2007 13:04 GMT
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
Mark Thornton - 01 Dec 2007 15:24 GMT
> API description says:
>
[quoted text clipped - 3 lines]
>
> 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
Drazen Gemic - 01 Dec 2007 16:39 GMT
> 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
Lew - 01 Dec 2007 16:59 GMT
>> As of Java 6 the JVM will check if two threads attempt to create
>> overlapping locks.

> This is what javase 6 API docs state:
>
[quoted text clipped - 6 lines]
> 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.

Signature

Lew

Mark Thornton - 01 Dec 2007 18:12 GMT
>> As of Java 6 the JVM will check if two threads attempt to create
>> overlapping locks.
[quoted text clipped - 11 lines]
>
> 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
Drazen Gemic - 01 Dec 2007 19:56 GMT
> 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
Mark Thornton - 01 Dec 2007 20:50 GMT
>> creation of an overlapping lock. However the 'proper' approach is to
>> create an object which manages the file(s) concerned and which is
[quoted text clipped - 12 lines]
> 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.
Lew - 01 Dec 2007 21:53 GMT
> 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();
    }
    // ...
  }
}

Signature

Lew

Drazen Gemic - 01 Dec 2007 22:22 GMT
> 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;
  }
}
Lew - 01 Dec 2007 22:42 GMT
>> You don't need to obtain the system class loader, just 'install' the
>> class files for this object in TomCat's classpath. Class loaders
[quoted text clipped - 19 lines]
> 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();
> //
[quoted text clipped - 10 lines]
>    {
>    try {

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

>       if(isLocked) wait();
>       }
[quoted text clipped - 16 lines]
>    }
> }

Signature

Lew

Drazen Gemic - 02 Dec 2007 15:59 GMT
> // 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
Zig - 01 Dec 2007 15:56 GMT
> API description says:
>
[quoted text clipped - 10 lines]
> 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
Drazen Gemic - 01 Dec 2007 16:21 GMT
> > API description says:
>
[quoted text clipped - 14 lines]
> 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) {
>         ...
[quoted text clipped - 5 lines]
> 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


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.