A bit of sugar for j.u.c.locks with try-with-resources?
Vitaly Davidovich
vitalyd at gmail.com
Sat Sep 3 18:22:28 UTC 2016
On Saturday, September 3, 2016, <forax at univ-mlv.fr> wrote:
> > De: "Dr Heinz M. Kabutz" <heinz at javaspecialists.eu <javascript:;>>
> > À: "Remi Forax" <forax at univ-mlv.fr <javascript:;>>
> > Cc: "Ivan Gerasimov" <ivan.gerasimov at oracle.com <javascript:;>>,
> "core-libs-dev"
> > <core-libs-dev at openjdk.java.net <javascript:;>>
> > Envoyé: Samedi 3 Septembre 2016 19:10:19
> > Objet: Re: A bit of sugar for j.u.c.locks with try-with-resources?
>
> > Not sure why the discussion keeps on going to EA with try-with-resource
> with
> > locks.
>
> > 1. There is no reason to construct objects, for example just write this
> class:
>
> > import java.util.concurrent.locks.*;
>
> > public class AutoLock implements AutoCloseable {
> > private final Lock lock;
>
> > public AutoLock(Lock lock) {
> > this.lock = lock;
> > }
>
> > public AutoLock lock() {
> > lock.lock();
> > return this;
> > }
>
> > public void close() {
> > lock.unlock();
> > }
> > }
>
> > And then use it as such:
>
> > import java.util.concurrent.locks.*;
>
> > public class AutoLockTest {
> > private final Lock lock = new ReentrantLock();
> > private final AutoLock al = new AutoLock(lock);
>
> > public void doSomething() {
> > try (AutoLock temp = al.lock()) {
> > // do something on the state
> > }
> > }
> > }
>
> > No objects are constructed.
> yes, you still pay the cost of an extra field in the class, an extra
> indirection when calling lock and unlock and an extra nullcheck (this one
> is hidden in the implementation of a try-with-resources).
> You may answer that ReentrantLock already pay the cost of an indirection
> over an AbstractQueuedSynchronizer (because a lock can be fair or unfair)
> so i suppose that an unfair implementation of AutoLock that directly
> extends AbstractQueuedSynchronizer should be faster or as fast as a
> ReentrantLock.
Right. This particular example can be worked around by having an extra
field. But it's a hack that besides the issues Remi lists, extends an
object's lifetime unnecessarily. You want sugar/ergonomics for the
try/finally usage, not anything beyond that.
>
> > 2. No one uses ReentrantLock anyway (unless they absolutely have to).
> See the
> > comment in Java 9 CopyOnWriteArrayList :-)
> > /**
> > * The lock protecting all mutators. (We have a mild preference
> > * for builtin monitors over ReentrantLock when either will do.)
> > */
> > final transient Object lock = new Object();
> yes, synchronized is more versatile until you have contention, want
> fairness, a tryLock or several Conditions.
Or lock and unlock aren't in the same scope/control flow.
>
> > 3. If you were to construct objects in the TWR block, they would be
> escaped in
> > my experience, except in the one case where there are multiple threads
> trying
> > to lock at the same time. However, in that case, ReentrantLock will
> anyway
> > create objects to manage the contention. But it really is a non-issue,
> since it
> > is trivial to code to not construct any objects with the TWR block in
> the first
> > place.
Again, in this particular case it's a non issue besides the downsides
already mentioned. Not all cases will be like that (e.g. you may receive a
resource as an arg and not have access to it anywhere else, and want the
ergonomics).
>
> > I keep getting asked this question all over the world. Personally I
> think it's a
> > non-issue, since the code is so trivial to write yourself, plus so few
> people
> > would use ReentrantLock anyway.
> > Regards
I know Kris started the thread in the context of a lock (and let's not
forget it could be some other impl besides RL), but there's a more general
pattern that's being discussed.
>
> regards,
> Rémi
>
> > Heinz
> > --
> > Dr Heinz M. Kabutz (PhD CompSci)
> > Author of "The Java(tm) Specialists' Newsletter"
> > Sun/Oracle Java Champion since 2005
> > JavaOne Rock Star Speaker 2012 http://www.javaspecialists.eu Tel: +30
> 69 75 595
> > 262
> > Skype: kabutz
>
> > Remi Forax wrote:
> >> ----- Mail original -----
>
> >>> De: "Ivan Gerasimov" <ivan.gerasimov at oracle.com <javascript:;>> À:
> "Krystal Mok"
> >>> <rednaxelafx at gmail.com <javascript:;>> , "core-libs-dev" <
> core-libs-dev at openjdk.java.net <javascript:;>>
> >>> Envoyé: Samedi 3 Septembre 2016 12:23:28
> >>> Objet: Re: A bit of sugar for j.u.c.locks with try-with-resources?
>
> >>> Hi Krystal!
>
> >>> On 03.09.2016 5:41, Krystal Mok wrote:
>
> >>>> Hi core-libs developers,
>
> >>>> I mostly live down in the VM world, but recently I've been playing
> with
> >>>> j.u.c.locks a bit, and saw that there's an opportunity to retrofit
> the API
> >>>> with the try-with-resources syntax. I wonder if anybody has brought
> this
> >>>> topic up before; apologies if there had been.
>
> >>>> >From the JavaDoc of j.u.c.l.ReentrantLock, the following is a
> typical usage:
>
> >>>> class X {
> >>>> private final ReentrantLock lock = new ReentrantLock();
> >>>> // ...
>
> >>>> public void m() {
> >>>> lock.lock(); // block until condition holds
> >>>> try {
> >>>> // ... method body
> >>>> } finally {
> >>>> lock.unlock()
> >>>> }
> >>>> }
> >>>> }
>
> >>> It could be written as
> >>> public void m() {
> >>> lock.lock(); // block until condition holds
> >>> try (Closeable unlocker = lock::unlock) {
> >>> // ... method body
> >>> }
> >>> }
>
> >>> This would save a couple of lines of code.
>
> >> but it does an allocation (if the escape analysis fails),
> >> i think it's better to wait for proper value types :)
>
> >>> With kind regards,
> >>> Ivan
>
> >> regards,
> >> Rémi
>
> >>>> The try...finally construction really pops out as a try-with-resources
> >>>> candidate.
>
> >>>> So what if we retrofit that with something like:
>
> >>>> class X {
> >>>> private final ReentrantLock lock = new ReentrantLock();
> >>>> // ...
>
> >>>> public void m() {
> >>>> try (lock.lock()) { // block until condition holds
> >>>> // ... method body
> >>>> } // automatic unlock at the end
> >>>> }
> >>>> }
>
> >>>> Assuming lock.lock() returns a temporary wrapper object (let's call
> it a
> >>>> "Locker" for this discussion), where Locker implements AutoCloseable,
> and
> >>>> its close() method calls lock.unlock().
> >>>> That'll make the API look and feel quite similar to the built-in
> >>>> "synchronized () { ... }" syntax. With escape analysis and scalar
> >>>> replacement implemented correctly in the VM, this temporary Locker
> object
> >>>> wouldn't incur much (or any) runtime cost after optimized JIT'ing, so
> it
> >>>> feels like a pure win to me.
>
> >>>> What do you think?
>
> >>>> Best regards,
> >>>> Kris (OpenJDK username: kmo)
>
--
Sent from my phone
More information about the core-libs-dev
mailing list