Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > synchronized using String.intern()

Reply
Thread Tools

synchronized using String.intern()

 
 
Paul J. Lucas
Guest
Posts: n/a
 
      01-30-2009
I've seen differing opinions on whether it will do as one would expect to do
something like:

synchronized ( myString.intern() ) {
// ...
}

that is: for a given, unique string (say "foo"), does String.intern() guarantee
that:

s.intern() == t.intern() iff s.equals( t )

assuming s != null && t != null? I.e., does it guarantee the same object for a
string composed of the same characters? If yes, then synchronizing on it should
work as one would expect, right?

The use case is to prevent concurrent access to a particular file, e.g.:

File f = ...;
synchoronzed ( f.getCanonicalPath().intern() ) {
// ...
}

If this will *not* work, why not? And how can I achieve what I want?

- Paul
 
Reply With Quote
 
 
 
 
Mark Space
Guest
Posts: n/a
 
      01-30-2009
Paul J. Lucas wrote:

> The use case is to prevent concurrent access to a particular file, e.g.:
>
> File f = ...;
> synchoronzed ( f.getCanonicalPath().intern() ) {
> // ...
> }
>
> If this will *not* work, why not? And how can I achieve what I want?


Concurrent access for your program? Or any running program (outside the
JVM)?

If the latter you're at the mercy of your OS. Look up file locking.
For the former, well, recent Java versions have file locking, so... use
that.
 
Reply With Quote
 
 
 
 
Lew
Guest
Posts: n/a
 
      01-30-2009
On Jan 30, 3:00*pm, "Paul J. Lucas" <(E-Mail Removed)> wrote:
> I've seen differing opinions on whether it will do as one would expect to do
> something like:
>
> * * * * synchronized ( myString.intern() ) {
> * * * * * *// ...
> * * * * }
>
> that is: for a given, unique string (say "foo"), does String.intern() guarantee
> that:
>
> * * * * s.intern() == t.intern() iff s.equals( t )
>
> assuming s != null && t != null? *I.e., does it guarantee the same object for a
> string composed of the same characters? *If yes, then synchronizing on it should
> work as one would expect, right?


Javadocs are your friend:
<http://java.sun.com/javase/6/docs/api/java/lang/String.html#intern()>
> for any two strings s and t,
> s.intern() == t.intern() is true if and only if s.equals(t) is true.


It uses almost the exact same wording that you did.

> The use case is to prevent concurrent access to a particular file, e.g.:


As Mark Space pointed out, synchronization between Java threads is not
related to file access.

> File f = ...;
> synchoronzed


Watch your spelling!

> * * * * ( f.getCanonicalPath().intern() ) {
> * * * * * * // ...
> * * * * }
>
> If this will *not* work, why not? *And how can I achieve what I want?


You will synchronize on the object that represents the canonical path
to the file. That canonical path will change depending on whether the
file exists or not, so the synchronization would end up being on
different objects, i.e., no synchronization at all.

There are ways to access the file without using the canonical path,
and those will not be synchronized.

None of the synchronization you do get will have anything to do with
file access, only with multithreaded execution of critical sections of
code within a single JVM.

The fact that the words "concurrent" and "synchronize" occur in
different contexts (memory, execution, file access) does not by itself
guarantee that the words mean the same thing across all contexts.
Different things are being synchronized in different ways for
different kinds of concurrency. In your example, even the things in
the same context, JVM threads, will be locking different objects and
not synchronizing correctly.

--
Lew

 
Reply With Quote
 
Tom Anderson
Guest
Posts: n/a
 
      01-30-2009
On Fri, 30 Jan 2009, Paul J. Lucas wrote:

> I've seen differing opinions on whether it will do as one would expect to do
> something like:
>
> synchronized ( myString.intern() ) {
> // ...
> }
>
> that is: for a given, unique string (say "foo"), does String.intern()
> guarantee that:
>
> s.intern() == t.intern() iff s.equals( t )
>
> assuming s != null && t != null? I.e., does it guarantee the same object for
> a string composed of the same characters? If yes, then synchronizing on it
> should work as one would expect, right?
>
> The use case is to prevent concurrent access to a particular file, e.g.:
>
> File f = ...;
> synchoronzed ( f.getCanonicalPath().intern() ) {
> // ...
> }
>
> If this will *not* work, why not? And how can I achieve what I want?


I think that's a pretty cunning hack, and i think it'll work.

Up to, as Lew says, degeneracy in the canonical path. If the file exists
before you start doing all this, and you're not using a case-insensitive
filesystem on an OS which doesn't handle it well (eg VFAT on linux), and
you don't have any hard links or other weirdness like bits of the local
filesystem mounted as loopback network shares etc floating around, you
should be fine.

tom

--
Only men's minds could have mapped into abstraction such a territory
 
Reply With Quote
 
Tom Anderson
Guest
Posts: n/a
 
      01-30-2009
On Fri, 30 Jan 2009, Paul J. Lucas wrote:

> Zig wrote:
>> It will return the same objects for two threads within the same VM. It
>> would obviously not lock the file from access by another process, including
>> another VM.

>
> Yes, I know (and I don't care about other VMs or processes).
>
>> Also, I think current VMs implement String.intern by adding unique values
>> to the Permanent Generation heap? Thus, the result of String.intern does
>> not get garbage collected. Using String.intern for many temporary strings
>> has been reported to lead to OutOfMemory errors.

>
> In my case, the number of such strings is guaranteed to be on the order of
> 1-10, so, again, I don't care.


I think i'd be looking for a way to refactor the architecture so that all
access to one of those files went through a single application object. I
would then either synchronize on that, or site a higher-level locking
mechanism there.

Something like:

class ApplicationFile {
private File file;
private ReadWriteLock lock;
public void addEntryToFile(Entry entry) {
if (!lock.writeLock().tryLock(200, MILLISECONDS))
throw new ApplicationException("timed out waiting to lock file " + file.getName());
try {
ADD ENTRY TO FILE GIVING FILE
}
finally {
lock.unlock();
}
}
public void doSomeOtherLowLevelOperationOfYourApplication() {
// similar to the above
}
// and more methods for the other low-level ops
}

I'd then stick the 1-10 of these that get used in a HashMap, and pull them
out and use them as needed.

Even better, rather than passing around strings in the app to identify
which file needs to be worked on, i'd pass references to the
ApplicationFile instances, to save on the lookup.

tom

--
Only men's minds could have mapped into abstraction such a territory
 
Reply With Quote
 
EJP
Guest
Posts: n/a
 
      01-31-2009
Paul J. Lucas wrote:
> I've seen differing opinions on whether it will do as one would expect
> to do something like:
>
> synchronized ( myString.intern() ) {
> // ...
> }
>
> that is: for a given, unique string (say "foo"), does String.intern()
> guarantee that:
>
> s.intern() == t.intern() iff s.equals( t )


That's what it says in the Javadoc. Any 'differing opinions' are uninformed.
 
Reply With Quote
 
Paul J. Lucas
Guest
Posts: n/a
 
      01-31-2009
Tom Anderson wrote:
> I think i'd be looking for a way to refactor the architecture so that
> all access to one of those files went through a single application
> object.


It already does.

> Even better, rather than passing around strings in the app to identify
> which file needs to be worked on, i'd pass references to the
> ApplicationFile instances, to save on the lookup.


The name of the file comes from an external source. I can't do the above.

- Paul
 
Reply With Quote
 
Daniel Pitts
Guest
Posts: n/a
 
      01-31-2009
Paul J. Lucas wrote:
> I've seen differing opinions on whether it will do as one would expect
> to do something like:
>
> synchronized ( myString.intern() ) {
> // ...
> }
>
> that is: for a given, unique string (say "foo"), does String.intern()
> guarantee that:
>
> s.intern() == t.intern() iff s.equals( t )
>
> assuming s != null && t != null? I.e., does it guarantee the same
> object for a string composed of the same characters? If yes, then
> synchronizing on it should work as one would expect, right?
>
> The use case is to prevent concurrent access to a particular file, e.g.:
>
> File f = ...;
> synchoronzed ( f.getCanonicalPath().intern() ) {
> // ...
> }
>
> If this will *not* work, why not? And how can I achieve what I want?
>
> - Paul

Nice try, but doesn't work...

Interned strings may be reclaimed by the garbage collector at any time,
so two successive calls to myString.intern() may not return the same
object (if the interned String instance wasn't stored somewhere).

You can do something like:

interface FileAccessor<T> {
T accessFile(File file) throws Exception;
}

public class FileAccessSynchronizer {
ConcurrentMap<String, Object> fileNameInUse =
new ConcurrentHashMap<String, Object>();

<T> T lockAndAccess(File file, FileAccessor<T> accessor)
throws Exception {
final Object myLock = new Object();
syncronize (myLock) {
try {
Object otherLock;
do {
otherLock = fileNameInUse.putIfAbsent(
file.getCanonicalPath(), myLock);
// If someone else has a registered lock:
if (otherLock != null) {
// Wait for them to release the lock.
syncronize (otherLock) {
// Grab it myself.
fileNameInUse.replace(file.getCanonicalPath(),
otherLock,
myLock);
}
}
} while (otherLock != null);
// do the work.
return accessor.accessFile(file);

} finally {
fileNameInUse.remove(file.getCanonicalPath(), myLock);
}
}
}

Then you can create any number of FileAccessor classes (even anonymous
ones), that access the file.

Note, this is untested, but it "looks right to me" (famous last words).

--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
 
Reply With Quote
 
Mark Space
Guest
Posts: n/a
 
      02-01-2009
Paul J. Lucas wrote:

>
> The name of the file comes from an external source. I can't do the above.


Just curious: what external source?

You can store file names in a Map, associating them to an object which
is synchronized. No need for intern, the Map will compare strings based
on equals() by default.

fileMap.put( filename, synchFile );
SyncrhonizedFile sf = fileMap.get( filename );

where filename is a String and SynchronizedFile is some class you create
to handle the IO synchronization. fileMap may have to be some sort of
global, which is bad. Try to inject it if possible. Be very certain
that this external source doesn't open any file handles of it's own, or
none of this will work.
 
Reply With Quote
 
Paul J. Lucas
Guest
Posts: n/a
 
      02-01-2009
Daniel Pitts wrote:
> Interned strings may be reclaimed by the garbage collector at any time,


How do you know that? The Javadoc doesn't say so.

> so two successive calls to myString.intern() may not return the same
> object (if the interned String instance wasn't stored somewhere).


(See: this is one of those "differing opinions" I referred to in my original post.)

[snip]

I just discovered that Java has FileLock. Couldn't I just use that? Does it
actually work as advertised cross-platform (at least Win, Mac, Linux)? Wouldn't
that be simpler?

- Paul
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Synchronized Block v.s. Synchronized Method Jerry Java 4 08-11-2010 02:34 PM
Question on synchronized and non synchronized methods ankur Java 4 11-28-2008 09:56 PM
Request for comments about synchronized queue using boost Nordl÷w C++ 15 10-22-2008 10:13 PM
synchronized block in synchronized static method dmcreyno Java 9 06-27-2006 07:43 PM
Use of synchronized variables over synchronized methods? Pep Java 6 08-15-2005 01:29 PM



Advertisments