AutoLock
Dr Heinz M. Kabutz
heinz at javaspecialists.eu
Mon Feb 28 11:07:03 PST 2011
Hi Joe, David,
thank you for humoring me regarding this issue. I understand all of
your rationales for not allowing simple expressions. I also agree with
Doug that we should not encourage people to write locking code, because
they will probably get it wrong. This will probably be my last comment
on this and then I'll go back to my hole on the island of Crete and shut
up ;-)
Here is a piece of code that returns the correct exception when used
with my AutoLock try-with-resource approach, but returns an unexpected
exception when used with the traditional await approach, also used in
the BlockingQueues:
import java.util.concurrent.locks.*;
public class StopTest {
private static Lock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
private static void incorrectExceptionReturned() throws
InterruptedException {
lock.lock();
try {
condition.await();
} catch (InterruptedException e) {
condition.signal();
throw e;
} finally {
lock.unlock();
}
}
private static void correctExceptionReturned() throws
InterruptedException {
try (AutoLock.lock(lock)) {
condition.await();
} catch(InterruptedException e) {
condition.signal();
throw e;
}
}
public static void main(String[] args)
throws InterruptedException {
Thread t1 = new Thread() {
public void run() {
try {
incorrectExceptionReturned();
} catch (Throwable t) {
System.out.println("incorrect exception: " + t);
t.printStackTrace(System.out);
}
}
};
Thread t2 = new Thread() {
public void run() {
try {
correctExceptionReturned();
} catch (Throwable t) {
System.out.println("correct exception: " + t);
t.printStackTrace(System.out);
}
}
};
t1.start();
t2.start();
Thread.sleep(100);
t1.stop();
Thread.sleep(100);
t2.stop();
}
}
I am calling the method stop(). Yes, I know it is deprecated. I know
it should never be called. I also know why :-) However, until it is
removed from the JDK (never?), it will remain there and programmers will
be able to call it. When I call stop() on a thread, I expect a
ThreadDeath. However, if it is in the await() state, it will come back
from the await() without getting the lock again. This means that we
will see the IllegalMonitorStateException, like so:
incorrect exception: java.lang.IllegalMonitorStateException
java.lang.IllegalMonitorStateException
at
java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:155)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1258)
at
java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:459)
at
eu.javaspecialists.concurrent.StopTest.incorrectExceptionReturned(StopTest.java:17)
at eu.javaspecialists.concurrent.StopTest.access$000(StopTest.java:5)
at eu.javaspecialists.concurrent.StopTest$1.run(StopTest.java:36)
correct exception: java.lang.ThreadDeath
java.lang.ThreadDeath
at java.lang.Thread.stop(Thread.java:828)
at eu.javaspecialists.concurrent.StopTest.main(StopTest.java:58)
Suppressed: java.lang.IllegalMonitorStateException
at
java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:155)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1258)
at
java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:459)
at eu.javaspecialists.concurrent.AutoLock.close(AutoLock.java:18)
at
eu.javaspecialists.concurrent.StopTest.correctExceptionReturned(StopTest.java:24)
at
eu.javaspecialists.concurrent.StopTest.access$100(StopTest.java:5)
at eu.javaspecialists.concurrent.StopTest$2.run(StopTest.java:46)
I understand this is a contrived example, because we should never call
stop(). But I still like the way that the try-with-resource returns the
correct throwable :-)
Regards
Heinz
--
Dr Heinz M. Kabutz (PhD CompSci)
Author of "The Java(tm) Specialists' Newsletter"
Sun Java Champion
IEEE Certified Software Development Professional
http://www.javaspecialists.eu
Tel: +30 69 72 850 460
Skype: kabutz
On 2/28/11 8:21 PM, Joe Darcy wrote:
> Hello.
>
> David Holmes wrote:
>> Hi Heinz,
>>
>> One slight glitch here is that, as I recall (and I'd like Joe to
>> confirm as I can't find anything in writing) they updated the spec to
>> disallow simple expressions, so you need to use something slightly
>> more verbose that introduces a local variable to refer to the Lock.
>>
>
> That is correct; the rationale for this change was given in:
> http://mail.openjdk.java.net/pipermail/coin-dev/2011-January/002972.html
>
>> Also as I understand it escape-analysis is only used by the server
>> compiler, so we can not rely on having it to get rid of the object
>> creation overhead. As indicated in the other threads on coin-dev
>> there are ways to do this without having to introduce a new object as
>> a wrapper - but they introduce their own overheads.
>>
>> By the way, the "whopping 553 classes" that implement AuoCloseable
>> comes about due to Closeable being retrofitted to also be
>> AutoCloseable. No big surprise that these are primarily (all?) I/O
>> related classes.
>>
> Most types that implement AutoCloseable do so by implementing
> java.io.Closeable. There are a few that just implement AutoCloseable:
>
> java.nio.channels.FileLock
> java.beans.XMLDecoder
> java.beans.XMLEncoder
> java.io.ObjectInput
> java.io.ObjectOutput
> java.sql.Connection
> java.sql.ResultSet
> java.sql.Statement
> javax.sound.midi.MidiDevice
> javax.sound.midi.Receiver
> javax.sound.sampled.Line
>
> Retrofitting JDBC with AutoCloseable occurred after the initial
> library changes [1]. For those wishing to retrofit types in a
> codebase to implement Closeable or AutoCloseable, an annotation
> processor is available to assist [2].
>
> -Joe
>
> [1] http://blogs.sun.com/darcy/entry/project_coin_jdbc_4_1
> [2] http://blogs.sun.com/darcy/entry/project_coin_bring_close
>
>
>> Cheers,
>> David Holmes
>>
>>
>> Dr Heinz M. Kabutz said the following on 02/28/11 05:30:
>>
>>> Hi,
>>>
>>> Brian told me about the discussion going on here on coin-dev. I
>>> published a newsletter today on the new Java 7 try-with-resource
>>> construct and how we could use it for automatically unlocking. By
>>> combining it with static imports, we can write the following code:
>>>
>>> try (lock(lock)) {
>>> printLockStatus();
>>> }
>>>
>>> Instead of the current more verbose
>>>
>>> lock.lock();
>>> try {
>>> printLockStatus();
>>> } finally {
>>> lock.unlock();
>>> }
>>>
>>> In my newsletter, I expressed the same concern as Neal, that
>>> constructing objects, and in fact encouraging people to do this in
>>> performance critical code, could be a killer for this idea.
>>>
>>> However, initial tests indicate that escape analysis actually does a
>>> nice job of eliminating the cost of the object construction. These
>>> are just completely basic initial tests and are quite possibly
>>> flawed. However, with the default escape analysis turned on, my try
>>> (lock(lock)) code did not cause any objects to be created, even
>>> though I called it 1_000_000_000 times.
>>>
>>> When I turned off escape analysis, it constructed about 30GB of
>>> objects.
>>>
>>> As I said, I have not tested this properly, just an initial
>>> investigation.
>>>
>>> Here is the link to my article:
>>> http://www.javaspecialists.eu/archive/Issue190.html
>>>
>>> Regards
>>>
>>> Heinz
>>>
>>
>>
>
>
More information about the coin-dev
mailing list