Named locks with String values

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Named locks with String values

Gregg Wonderly-2
I recently was working on some code where a method had to string values comming
into it, and these values indicate a SQL database rowset that I want to lock
access to.  I was trying to decide how I wanted to the locking and then it
dawned on me that I could do the following.

        public void getEntries( String use, String key, ... ) {
                synchronized( (use+"/"+key).intern() ) {
                        ...
                }
        }

I quick check with and without the intern() call validated that the uniqueness
of intern() appeared to provide the locking that I needed.

I haven't seen String.intern() mentioned here as a way to get named locks and so
I was curious of others comments about this usage and whether there are other
interesting exploits of using other JVM caches.

I understand that this can cause some extended memory growth if use and key are
not reasonably bounded in possible values.

Gregg Wonderly
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Named locks with String values

Dawid Kurzyniec
Gregg Wonderly wrote:

> I recently was working on some code where a method had to string
> values comming into it, and these values indicate a SQL database
> rowset that I want to lock access to.  I was trying to decide how I
> wanted to the locking and then it dawned on me that I could do the
> following.
>
>     public void getEntries( String use, String key, ... ) {
>         synchronized( (use+"/"+key).intern() ) {
>             ...
>         }
>     }
>
I was hoping that some EG member would comment, but in the absence of that:

This looks reasonably legit to me, although feels a bit risky. One
possible caveat is that it is "external" synchronization, and some other
library used by your program might independently have the same idea.
Then you can possibly get into deadlocks: even if you enforce consistent
lock ordering, or if your code never obtains more than a single lock,
when combined with unknown library code, it may result in trying to
acquire two locks from two threads in a different order.

> I understand that this can cause some extended memory growth if use
> and key are not reasonably bounded in possible values.

I think that smart enough JVM would make the intern cache weak, but you
never know.

All in all, I would probably rather implement my own weak named lock
pool, just to be sure that nothing bad like that can happen.

Regards,
Dawid

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Named locks with String values

Gregg Wonderly-3
Dawid Kurzyniec wrote:

> Gregg Wonderly wrote:
>
>> I recently was working on some code where a method had to string
>> values comming into it, and these values indicate a SQL database
>> rowset that I want to lock access to.  I was trying to decide how I
>> wanted to the locking and then it dawned on me that I could do the
>> following.
>>
>>     public void getEntries( String use, String key, ... ) {
>>         synchronized( (use+"/"+key).intern() ) {
>>             ...
>>         }
>>     }
>>
> I was hoping that some EG member would comment, but in the absence of that:
>
> This looks reasonably legit to me, although feels a bit risky. One
> possible caveat is that it is "external" synchronization, and some other
> library used by your program might independently have the same idea.

What this is controlling is the synchronization of a set of property values in a
database.  There are multiple threads that are able to delete all and insert all
of the properties as they encounter information during startup.  What happens is
that one thread will delete all the properties, and then another, will run a
query and find them all missing, and say ohh I need to update these.  Both
threads will then try the inserts, one or more of which will fail with a
duplicate key error.  This synchronization is only needed briefly, and is, in
fact isolated to just the threads running in this JVM.  All other users of the
data are read-only users.

It does feel a bit risky, to me as well, but it was a quick way to see that I
had in fact found the location of conflicting access.  I can, of course, create
a real weakhashmap of locks, as I suggested in my other followup.  And, I
probably will.  But, I just found this to be an interesting quick and easy way
to create a named locking mechanism.  It's not ultimate, nor, perhaps even
realistic to use, but just something that came to mind.

Gregg Wonderly
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Named locks with String values

Dawid Kurzyniec
Gregg Wonderly wrote:

> Dawid Kurzyniec wrote:
>
>> Gregg Wonderly wrote:
>>
>>> I recently was working on some code where a method had to string
>>> values comming into it, and these values indicate a SQL database
>>> rowset that I want to lock access to.  I was trying to decide how I
>>> wanted to the locking and then it dawned on me that I could do the
>>> following.
>>>
>>>     public void getEntries( String use, String key, ... ) {
>>>         synchronized( (use+"/"+key).intern() ) {
>>>             ...
>>>         }
>>>     }
>>>
>> I was hoping that some EG member would comment, but in the absence of
>> that:
>>
>> This looks reasonably legit to me, although feels a bit risky. One
>> possible caveat is that it is "external" synchronization, and some
>> other library used by your program might independently have the same
>> idea.
>
>
> What this is controlling is the synchronization of a set of property
> values in a database.  There are multiple threads that are able to
> delete all and insert all of the properties as they encounter
> information during startup.  What happens is that one thread will
> delete all the properties, and then another, will run a query and find
> them all missing, and say ohh I need to update these.  Both threads
> will then try the inserts, one or more of which will fail with a
> duplicate key error.  This synchronization is only needed briefly, and
> is, in fact isolated to just the threads running in this JVM.  All
> other users of the data are read-only users.
>
> It does feel a bit risky, to me as well, but it was a quick way to see
> that I had in fact found the location of conflicting access.  I can,
> of course, create a real weakhashmap of locks, as I suggested in my
> other followup.  And, I probably will.  But, I just found this to be
> an interesting quick and easy way to create a named locking
> mechanism.  It's not ultimate, nor, perhaps even realistic to use, but
> just something that came to mind.

You're welcome to use:
http://dcl.mathcs.emory.edu/cgi-bin/viewcvs.cgi/software/util/src/edu/emory/mathcs/util/remote/locks/ReentrantDistributedLock.java?view=markup

To make this work in your scenario, you need either to modify the class
a bit, or to write a dummy RemoteLock class, ensapsulating String
instance, implementing equals and hashCode by delegating to that string,
and otherwise having all operations no-op. Then, you can do:

Lock lock = new ReentrantDistributedLock(new DummyRemoteLock("foo"));
lock.lock();
try { ... } finally { lock.unlock(); }

Or even:

Lock lock = new ReentrantDistributedLock(new DummyRemoteLock("foo"));
lock.lock();
try { ... }
finally {
  lock = new ReentrantDistributedLock(new DummyRemoteLock("foo"));
  lock.unlock();
}

Of course you can write a factory method in DummyRemoteLock to simplify
the invocation syntax, perhaps like this:

Lock lock = MyClass.lock("foo");
try { ... } finally { lock.unlock(); }

This class was designed for a bit more complex general case, where you
need a distributed lock accessed by many JVMs and threads. Its purpose
is to provide reentrancy and resolve local mutual exclusion within the
JVM, so that threads within a single JVM do not contend on a remote
lock, but only on the local lock, and so that a thread who obtained the
lock does not make remote calls to re-enter the lock. We used it, with
some other helper classes providing generic versions of CAS-based and
Eisenberg-McGuire algorithms, to implement poor-man's distributed
locking piggybacking on JNDI.

Regards,
Dawid

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest