Unsafe: removing the monitorEnter/monitorExit/tryMonitorEnter methods
Peter Levart
peter.levart at gmail.com
Thu Feb 27 11:52:16 UTC 2014
On 02/27/2014 10:58 AM, David Holmes wrote:
> On 27/02/2014 6:38 PM, Peter Levart wrote:
>> On 02/27/2014 08:41 AM, David Holmes wrote:
>>> On 27/02/2014 5:30 PM, Peter Levart wrote:
>>>> On 02/27/2014 08:29 AM, Peter Levart wrote:
>>>>> On 02/26/2014 09:54 PM, Martin Buchholz wrote:
>>>>>> I don't recall having added this particular wart
>>>>>> to test/java/lang/ProcessBuilder/Basic.java, and history suggests
>>>>>> that
>>>>>> others did that.
>>>>>>
>>>>>> 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.
>>>>>
>>>>> Thread.holdsLock(Object) ?
>>>>
>>>> Ah, you meant to query from some other thread, right?
>>>
>>> Right - that is the usage in Basic.java but I'm still scratching my
>>> head trying to understand what finding the BufferedInputStream locked
>>> is supposed to signify.
>>
>> Here's the relevant code block:
>>
>> while (unsafe.tryMonitorEnter(s)) {
>> unsafe.monitorExit(s);
>> Thread.sleep(1);
>> }
>>
>> This code block waits until it finds that some thread has acquired the
>> lock on 's' for at least 1 ms (or else it can miss it and will wait
>> further) ...
>>
>> Since this block is executed for s instanceof BufferedInputStream, what
>> this block does, is wait until one of synchronized methods on
>> BufferedInputStream is called. The thread that does that, calls read()
>> or read(byte[]) and blocks while holding a lock, since the child process
>> that is spawned and whose stdout the thread is trying to read in this
>> situation does a 10 minute sleep.
>
> Ah I see - thanks for the analysis. So this is a classic 'barrier'
> waiting for the other thread to have reached the synchronized method.
>
>> I think the following could be used instead for the same purpose:
>>
>> while (!isLocked(s, 100L)) {
>> Thread.sleep(1);
>> }
>>
>> // using the following utility method:
>>
>> static boolean isLocked(final Object monitor, long millis) throws
>> InterruptedException {
>> Thread t = new Thread() {
>> @Override
>> public void run() {
>> synchronized (monitor) { }
>> }
>> };
>> t.start();
>> t.join(millis);
>> return t.isAlive();
>> }
>
> Functionally yes this will only return true if the object is locked
> for >100ms. But it is potentially going to generate a lot of temporary
> threads. And in theory at least the JIT can optimize the run method
> into nothing.
Ok, then what about the following:
static boolean isLocked(final Object monitor, final long millis)
throws InterruptedException {
return new Thread() {
volatile boolean unlocked;
@Override
public void run() {
synchronized (monitor) { unlocked = true; }
}
boolean isLocked() throws InterruptedException {
start();
join(millis);
return !unlocked;
}
}.isLocked();
}
// and usage it like:
while (!isLocked(s, 100L)) {
Thread.sleep(100L);
}
This will allocate about 10 Thread objects per second until the other
thread finally reaches the synchronized read() method in
BufferedInputStream...
Regards, Peter
>
> Still it is a cute trick :)
>
> David
>
>>
>> Regards, Peter
>>
>>>
>>> David
>>> -----
>>>
>>>> Peter
>>>>
>>>>>
>>>>> Regards, Peter
>>>>>
>>>>>>
>>>>>>
>>>>>> On Wed, Feb 26, 2014 at 7:12 AM, Paul Sandoz
>>>>>> <paul.sandoz at oracle.com>
>>>>>> wrote:
>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> Out of all the methods on Unsafe i think the
>>>>>>> monitorEnter/monitorExit/tryMonitorEnter are the least used and are
>>>>>>> very
>>>>>>> strong candidates for removal.
>>>>>>>
>>>>>>> 99% of use-cases are supported by classes in the
>>>>>>> java.util.concurrent.locks package.
>>>>>>>
>>>>>>>
>>>>>>> Within the JDK itself it is only used in one JDK test file
>>>>>>> test/java/lang/ProcessBuilder/Basic.java:
>>>>>>>
>>>>>>> while (unsafe.tryMonitorEnter(s)) {
>>>>>>> unsafe.monitorExit(s);
>>>>>>> Thread.sleep(1);
>>>>>>> }
>>>>>>>
>>>>>>> for a test verifying an EOF is received on pending reads and it is
>>>>>>> polling
>>>>>>> to check when the process builder acquires the lock before
>>>>>>> destroying the
>>>>>>> process, presumably to avoid some sort of race condition that
>>>>>>> occasionally
>>>>>>> causes the test to fail.
>>>>>>>
>>>>>>> I believe this test as been through a number of rounds, i stared
>>>>>>> at public static boolean isLocked(final Object monitor,
>>>>>>> final long millis) throws InterruptedException {
>>>>>>> return new Thread() {
>>>>>>> volatile boolean unlocked;
>>>>>>>
>>>>>>> @Override
>>>>>>> public void run() {
>>>>>>> synchronized (monitor) { unlocked = true; }
>>>>>>> }
>>>>>>>
>>>>>>> boolean isLocked() throws InterruptedException {
>>>>>>> start();
>>>>>>> join(millis);
>>>>>>> return !unlocked;
>>>>>>> }
>>>>>>> }.isLocked();
>>>>>>> }
>>>>>>>
>>>>>>> things
>>>>>>> for a bit, but cannot quickly work out a replacement; i lack the
>>>>>>> knowledge
>>>>>>> on this area.
>>>>>>>
>>>>>>>
>>>>>>> Outside of the JDK i can only find one usage of monitorExit/Enter
>>>>>>> (according to grep code) in JBoss modules, and i believe this is
>>>>>>> only used
>>>>>>> on Java 1.6 to work around some limitations in class loading that
>>>>>>> were
>>>>>>> fixed in 1.7.
>>>>>>>
>>>>>>>
>>>>>>> Given such very limited use i propose to remove these methods after
>>>>>>> having
>>>>>>> worked out a fix for ProcessBuilder/Basic.java test.
>>>>>>>
>>>>>>> Paul.
>>>>>>>
>>>>>
>>>>
>>
More information about the core-libs-dev
mailing list