Unsafe: removing the monitorEnter/monitorExit/tryMonitorEnter methods
David Holmes
david.holmes at oracle.com
Tue Mar 4 04:09:07 UTC 2014
On 4/03/2014 1:45 PM, David Holmes wrote:
> On 3/03/2014 10:56 PM, David M. Lloyd wrote:
>> Yes, that would necessarily be the contract of a Monitors class, just as
>> it is part of the contract of Lock today. If your argument is that it
>> shouldn't be allowed because it might be used wrong, we might as well
>> just delete most of the JDK, ReentrantLock included, since it suffers
>> from the exact same potential problem. The difference is that monitors
>> have a simple API in the form of synchronized that people were in the
>> past and would continue to be free (and recommended) to use.
>
> We should not introduce anything that allows something that was
> guaranteed to be safe by the language, to become unsafe. So I can
> support a call for tryMonitorEnter, but not for explicit enter/exit
> actions.
Which of course is not possible at the API level - Doh! Sorry.
David
> David
> -----
>
>> I would not call recommending monitors to be a "premature optimization".
>> The memory overhead of ReentrantLock is far too large for many use
>> cases, especially when it comes to fine-grained locking of large data
>> sets. In fact I would *only* recommend Lock if your need for the extra
>> behavior it provides (i.e., multiple conditions, tryLock, timed tryLock,
>> and/or interruptible locking) or for the extra behavior provided by
>> ReentrantLock itself (i.e., lock status introspection) outweighs the
>> cost of its memory consumption, which so far has happened zero times in
>> any of the many frameworks I maintain.
>>
>> On the other hand, adding some of the missing functionality to a
>> Monitors class would be pretty handy, especially if doing so doesn't
>> create a large divergence from the existing implementation. Given that
>> tryMonitorEnter already exists, implementing that method on a Monitors
>> class seems fairly trivial, which already takes care of one out of the
>> four special use cases for Locks. Interruptible locking would be my
>> first choice for a number two, if this idea were actually officially on
>> the table. Finally, an isMonitorHeld() method would tie in another
>> branch of the discussion nicely and seems trivially possible as well.
>> Any other information would be a purely
>>
>> It's worth noting that it's already possible for user code to implement
>> the basic functionality using JNI methods, though in the interest of
>> full disclosure it's worth noting that the enter/exit monitor JNI
>> functions are forbidden by spec to interoperate with the corresponding
>> bytecodes.
>>
>> FWIW using the word "monitor" instead of "lock" may help avoid confusion
>> and "scare off" those pesky undergrads.
>>
>> On 03/02/2014 12:48 PM, Dr Heinz M. Kabutz wrote:
>>> Hi Dave,
>>>
>>> "lighter" is subject to the HotSpot Profiler doing the optimizations
>>> that you expect. Problem is, once you begin manually locking /
>>> unlocking monitors, the byte codes are not recognizable as standard
>>> synchronized(monitor) {} code, thus the optimizations will also not be
>>> as good (or completely absent). At least that has been my experience
>>> when I tried it out a few years ago. So the argument that synchronized
>>> is faster than ReentrantLock, besides this being IMHO a premature
>>> optimization, cannot be directly applied to when we manually do use the
>>> monitorEnter/monitorExit methods.
>>>
>>> The reason why I personally think they are more dangerous than
>>> ReentrantLock is that we are used to synchronized() {} taking care of
>>> the unlocking for us. If we see a thread that is in the BLOCKED state
>>> (which only happens with synchronized) then we would typically assume
>>> that another thread is /currently /holding the monitor.
>>>
>>> Take the following example code:
>>>
>>> import sun.misc.*;
>>>
>>> import java.lang.reflect.*;
>>>
>>> public class MonitorMystery {
>>> public static Unsafe getUnsafe() {
>>> try {
>>> for (Field field : Unsafe.class.getDeclaredFields()) {
>>> if (Modifier.isStatic(field.getModifiers())) {
>>> if (field.getType() == Unsafe.class) {
>>> field.setAccessible(true);
>>> return (Unsafe) field.get(null);
>>> }
>>> }
>>> }
>>> throw new IllegalStateException("Unsafe field not found");
>>> } catch (Exception e) {
>>> throw new IllegalStateException(
>>> "Could not initialize unsafe", e);
>>> }
>>> }
>>>
>>> public static void main(String... args) throws InterruptedException {
>>> Thread t = new Thread() {
>>> public void run() {
>>> getUnsafe().monitorEnter(MonitorMystery.class);
>>> }
>>> };
>>> t.start();
>>> Thread.sleep(100);
>>> System.out.println("Trying to synchronize");
>>> synchronized (MonitorMystery.class) {
>>> System.out.println("Managed to synchronized");
>>> }
>>> }
>>> }
>>>
>>> We now see that we never manage to synchronize in the main thread and in
>>> fact if you do a thread dump you will see a deadlock involving only a
>>> single thread :-)
>>>
>>> This is why it is so important to use the correct idioms. In my
>>> experience, there are very few Java programmers who get this right.
>>> Brian Goetz's book is correct, but there are other books out there that
>>> do a shocking job of mangling the idiom.
>>>
>>> Whenever possible, use synchronized() { }. If not, IMHO it would be
>>> preferable to switch to ReentrantLock.
>>>
>>> Regards
>>>
>>> Heinz
>>> --
>>> Dr Heinz M. Kabutz (PhD CompSci)
>>> Author of "The Java(tm) Specialists' Newsletter"
>>> Oracle Java Champion 2005-2013
>>> JavaOne Rock Star Speaker 2012
>>> http://www.javaspecialists.eu
>>> Tel: +30 69 75 595 262
>>> Skype: kabutz
>>>
>>>
>>>
>>> David M. Lloyd wrote:
>>>> Making the language Kindergarten-friendly at the cost of general
>>>> usefulness is a mistake, IMO. And anyway there's nothing that is less
>>>> safe about a Monitors class than ReentrantLock; on the other hand,
>>>> monitors continue to be considerably lighter (size and (for most of
>>>> the history of JUC) speed) by every measurement I've ever made. I
>>>> would advise monitors over ReentrantLock 9 times out of 10 in any of
>>>> our code.
>>>>
>>>> I just don't think your metaphors - neither of monitor methods being
>>>> dangerous, nor of Java developers being infants - are really apt.
>>>>
>>>> On 03/02/2014 02:51 AM, Dr Heinz M. Kabutz wrote:
>>>>> With a curious 9 months old crawling around the house, I've just moved
>>>>> the sharp knives to the top draw in the kitchen - out of reach. I
>>>>> don't
>>>>> think we should be encouraging people to use monitor.tryLock() for
>>>>> various reasons:
>>>>>
>>>>> 1. We have a richer interface with Lock/ReentrantLock, including
>>>>> better
>>>>> Condition that allow easier timed wait idioms.
>>>>>
>>>>> 2. It is just too easy to get the idioms wrong for Lock.lock() and
>>>>> Lock.unlock(). Every time I show this idiom some people in the
>>>>> audience
>>>>> start arguing with me:
>>>>>
>>>>> lock.lock();
>>>>> try {
>>>>> // do something
>>>>> } finally {
>>>>> lock.unlock();
>>>>> }
>>>>>
>>>>> IMHO, this is really an edge case that might be useful to have
>>>>> semi-accessible at some point, but not something that should generally
>>>>> be done. It belongs in the same draw as the sharp knives and the
>>>>> ability to cause arbitrary asynchronous exceptions (which has been
>>>>> made
>>>>> more difficult to do in Java 8).
>>>>>
>>>>> Brian Goetz wrote:
>>>>>> Except that Lock has features that are not supported by intrinsic
>>>>>> locks (timed wait, interruptible wait.) So the Lock returned would
>>>>>> not conform to Lock's contract, and attempting to call these methods
>>>>>> would probably throw UOE.
>>>>>>
>>>>>> On 2/27/2014 6:12 AM, Stephen Colebourne wrote:
>>>>>>> On 26 February 2014 20:54, Martin Buchholz <martinrb at google.com>
>>>>>>> wrote:
>>>>>>>> It does seem that being able to tell whether a java object
>>>>>>>> monitor is
>>>>>>>> currently locked is useful for debugging and monitoring - there
>>>>>>>> should be a
>>>>>>>> way to do that.
>>>>>>>
>>>>>>> Perhaps it would be useful to be able to expose a java object
>>>>>>> monitor
>>>>>>> as an instance of Lock?
>>>>>>>
>>>>>>> Lock lk = Lock.ofMonitor(object)
>>>>>>> if (lk.tryLock()) {
>>>>>>> ...
>>>>>>> }
>>>>>>>
>>>>>>> Such a method feels like it would be a useful missing link between
>>>>>>> synchronized and locks.
>>>>>>>
>>>>>>> Stephen
>>>>>>>
>>>>>>
>>>>
>>>>
>>
>>
More information about the core-libs-dev
mailing list