Unsafe: removing the monitorEnter/monitorExit/tryMonitorEnter methods
Peter Levart
peter.levart at gmail.com
Tue Mar 4 07:01:46 UTC 2014
On 03/04/2014 05:09 AM, David Holmes wrote:
> 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.
Unless the API is made safe by packing it into a lambda-consuming
method. For example:
public static boolean trySynchronized(Runnable action);
Regards, Peter
>
> 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