Unsafe.park/unpark, j.u.c.LockSupport and Thread
Hi, As part of the effort around Unsafe (some may have noticed some cleanup work) i have been recently looking at the park/unpark methods. The class java.util.concurrent.locks.LockSupport [1] has some thin public wrappers around these methods: public static void unpark(Thread thread) { if (thread != null) U.unpark(thread); } public static void park() { U.park(false, 0L); } public static void parkNanos(long nanos) { if (nanos > 0) U.park(false, nanos); } public static void parkUntil(long deadline) { U.park(true, deadline); } Is not clear to me what is exactly unsafe about park/unpark and why they were not originally placed on Thread itself given the above wrapping. There is mention of unpark being unsafe with regards to native code and ensuring the thread has not been destroyed: /** * Unblock the given thread blocked on <tt>park</tt>, or, if it is * not blocked, cause the subsequent call to <tt>park</tt> not to * block. Note: this operation is "unsafe" solely because the * caller must somehow ensure that the thread has not been * destroyed. Nothing special is usually required to ensure this * when called from Java (in which there will ordinarily be a live * reference to the thread) but this is not nearly-automatically * so when calling from native code. * @param thread the thread to unpark. * */ public native void unpark(Object thread); However, native code is anyway inherently unsafe. In addition this class has a cosy relationship with Thread (it wants to poke into Thread's non-public fields): // Hotspot implementation via intrinsics API private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe(); private static final long PARKBLOCKER; private static final long SEED; private static final long PROBE; private static final long SECONDARY; static { try { PARKBLOCKER = U.objectFieldOffset (Thread.class.getDeclaredField("parkBlocker")); SEED = U.objectFieldOffset (Thread.class.getDeclaredField("threadLocalRandomSeed")); PROBE = U.objectFieldOffset (Thread.class.getDeclaredField("threadLocalRandomProbe")); SECONDARY = U.objectFieldOffset (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed")); } catch (ReflectiveOperationException e) { throw new Error(e); } } Although only PARKBLOCKER and SECONDARY are used AFAICT. I am sure there is some history behind all this... but in my ignorance of the past perhaps it's time to reconsider? We could reduce the coupling on Thread and dependency on Unsafe if we consider moving park/unpark and LockSupport functionality to Thread itself. Thoughts? Paul. [1] http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concu...
Hi Paul, When we added j.u.c there was reluctance to add these methods to Thread - this was the normal policy (for the time) of don't touch the core classes. So LockSupport is the public API and Unsafe was chosen as the implementation as it is a de-facto interface to the VM from JDK code rather then defining explicit native methods (I must admit I'm unsure why we went this route rather than simply hooking into jvm.cpp with JVM_park/JVM_unpark. I think in many ways it was/is just easier to call an Unsafe method and define a new unsafe.cpp native call. Plus we had a bunch of other Unsafe API's being used from j.u.c.) So we can't just move things from LockSupport to Thread as we'd need to deprecate first etc etc. But I don't see any reason why we couldn't move the implementation from unsafe.cpp to jvm.cpp and invoke via a native method implementation of LockSupport. It would still be just as "unsafe" of course. Aside: this is where the infamous "spurious wakeup" from park() can arise. If you just randomly unpark() a Thread there is nothing to guarantee that the thread doesn't terminate and free its native resources while you are working on it. But the ParkEvents are type-stable-memory, so even if the event has been disassociated from the target thread you can still call unpark() as it is never freed. However if that ParkEvent has since been reused by another thread, then that thread will encounter a "spurious wakeup" if it calls park(). Cheers, David On 10/02/2015 8:49 PM, Paul Sandoz wrote:
Hi,
As part of the effort around Unsafe (some may have noticed some cleanup work) i have been recently looking at the park/unpark methods.
The class java.util.concurrent.locks.LockSupport [1] has some thin public wrappers around these methods:
public static void unpark(Thread thread) { if (thread != null) U.unpark(thread); }
public static void park() { U.park(false, 0L); }
public static void parkNanos(long nanos) { if (nanos > 0) U.park(false, nanos); }
public static void parkUntil(long deadline) { U.park(true, deadline); }
Is not clear to me what is exactly unsafe about park/unpark and why they were not originally placed on Thread itself given the above wrapping.
There is mention of unpark being unsafe with regards to native code and ensuring the thread has not been destroyed:
/** * Unblock the given thread blocked on <tt>park</tt>, or, if it is * not blocked, cause the subsequent call to <tt>park</tt> not to * block. Note: this operation is "unsafe" solely because the * caller must somehow ensure that the thread has not been * destroyed. Nothing special is usually required to ensure this * when called from Java (in which there will ordinarily be a live * reference to the thread) but this is not nearly-automatically * so when calling from native code. * @param thread the thread to unpark. * */ public native void unpark(Object thread);
However, native code is anyway inherently unsafe.
In addition this class has a cosy relationship with Thread (it wants to poke into Thread's non-public fields):
// Hotspot implementation via intrinsics API private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe(); private static final long PARKBLOCKER; private static final long SEED; private static final long PROBE; private static final long SECONDARY; static { try { PARKBLOCKER = U.objectFieldOffset (Thread.class.getDeclaredField("parkBlocker")); SEED = U.objectFieldOffset (Thread.class.getDeclaredField("threadLocalRandomSeed")); PROBE = U.objectFieldOffset (Thread.class.getDeclaredField("threadLocalRandomProbe")); SECONDARY = U.objectFieldOffset (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed")); } catch (ReflectiveOperationException e) { throw new Error(e); } }
Although only PARKBLOCKER and SECONDARY are used AFAICT.
I am sure there is some history behind all this... but in my ignorance of the past perhaps it's time to reconsider?
We could reduce the coupling on Thread and dependency on Unsafe if we consider moving park/unpark and LockSupport functionality to Thread itself.
Thoughts?
Paul.
[1] http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concu...
Oh I just realized/remembered why we use Unsafe for this - it is because of the potential for intrinsics. David On 10/02/2015 10:02 PM, David Holmes wrote:
Hi Paul,
When we added j.u.c there was reluctance to add these methods to Thread - this was the normal policy (for the time) of don't touch the core classes. So LockSupport is the public API and Unsafe was chosen as the implementation as it is a de-facto interface to the VM from JDK code rather then defining explicit native methods (I must admit I'm unsure why we went this route rather than simply hooking into jvm.cpp with JVM_park/JVM_unpark. I think in many ways it was/is just easier to call an Unsafe method and define a new unsafe.cpp native call. Plus we had a bunch of other Unsafe API's being used from j.u.c.)
So we can't just move things from LockSupport to Thread as we'd need to deprecate first etc etc. But I don't see any reason why we couldn't move the implementation from unsafe.cpp to jvm.cpp and invoke via a native method implementation of LockSupport. It would still be just as "unsafe" of course.
Aside: this is where the infamous "spurious wakeup" from park() can arise. If you just randomly unpark() a Thread there is nothing to guarantee that the thread doesn't terminate and free its native resources while you are working on it. But the ParkEvents are type-stable-memory, so even if the event has been disassociated from the target thread you can still call unpark() as it is never freed. However if that ParkEvent has since been reused by another thread, then that thread will encounter a "spurious wakeup" if it calls park().
Cheers, David
On 10/02/2015 8:49 PM, Paul Sandoz wrote:
Hi,
As part of the effort around Unsafe (some may have noticed some cleanup work) i have been recently looking at the park/unpark methods.
The class java.util.concurrent.locks.LockSupport [1] has some thin public wrappers around these methods:
public static void unpark(Thread thread) { if (thread != null) U.unpark(thread); }
public static void park() { U.park(false, 0L); }
public static void parkNanos(long nanos) { if (nanos > 0) U.park(false, nanos); }
public static void parkUntil(long deadline) { U.park(true, deadline); }
Is not clear to me what is exactly unsafe about park/unpark and why they were not originally placed on Thread itself given the above wrapping.
There is mention of unpark being unsafe with regards to native code and ensuring the thread has not been destroyed:
/** * Unblock the given thread blocked on <tt>park</tt>, or, if it is * not blocked, cause the subsequent call to <tt>park</tt> not to * block. Note: this operation is "unsafe" solely because the * caller must somehow ensure that the thread has not been * destroyed. Nothing special is usually required to ensure this * when called from Java (in which there will ordinarily be a live * reference to the thread) but this is not nearly-automatically * so when calling from native code. * @param thread the thread to unpark. * */ public native void unpark(Object thread);
However, native code is anyway inherently unsafe.
In addition this class has a cosy relationship with Thread (it wants to poke into Thread's non-public fields):
// Hotspot implementation via intrinsics API private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe(); private static final long PARKBLOCKER; private static final long SEED; private static final long PROBE; private static final long SECONDARY; static { try { PARKBLOCKER = U.objectFieldOffset (Thread.class.getDeclaredField("parkBlocker")); SEED = U.objectFieldOffset
(Thread.class.getDeclaredField("threadLocalRandomSeed")); PROBE = U.objectFieldOffset
(Thread.class.getDeclaredField("threadLocalRandomProbe")); SECONDARY = U.objectFieldOffset
(Thread.class.getDeclaredField("threadLocalRandomSecondarySeed")); } catch (ReflectiveOperationException e) { throw new Error(e); } }
Although only PARKBLOCKER and SECONDARY are used AFAICT.
I am sure there is some history behind all this... but in my ignorance of the past perhaps it's time to reconsider?
We could reduce the coupling on Thread and dependency on Unsafe if we consider moving park/unpark and LockSupport functionality to Thread itself.
Thoughts?
Paul.
[1] http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concu...
Hi David, On Feb 10, 2015, at 1:02 PM, David Holmes <david.holmes@oracle.com> wrote:
Hi Paul,
When we added j.u.c there was reluctance to add these methods to Thread - this was the normal policy (for the time) of don't touch the core classes. So LockSupport is the public API and Unsafe was chosen as the implementation as it is a de-facto interface to the VM from JDK code rather then defining explicit native methods (I must admit I'm unsure why we went this route rather than simply hooking into jvm.cpp with JVM_park/JVM_unpark. I think in many ways it was/is just easier to call an Unsafe method and define a new unsafe.cpp native call. Plus we had a bunch of other Unsafe API's being used from j.u.c.)
So we can't just move things from LockSupport to Thread as we'd need to deprecate first etc etc.
I was thinking that the implementation of LockSupport could be updated to use any new stuff we could add to java.lang.{*, Thread}. I am trying to tease apart the internal dependencies that 166 classes have on the platform. In the case of LockSupport there are two, Unsafe and Thread. Adding native methods to 166 classes will introduce another form of dependency on the platform that i would prefer to avoid.
But I don't see any reason why we couldn't move the implementation from unsafe.cpp to jvm.cpp and invoke via a native method implementation of LockSupport. It would still be just as "unsafe" of course.
Can you think of any reasons, beyond that of "don't touch the core classes", why we cannot copy this functionality over to java.lang.{*, Thread} ?
Aside: this is where the infamous "spurious wakeup" from park() can arise. If you just randomly unpark() a Thread there is nothing to guarantee that the thread doesn't terminate and free its native resources while you are working on it. But the ParkEvents are type-stable-memory, so even if the event has been disassociated from the target thread you can still call unpark() as it is never freed. However if that ParkEvent has since been reused by another thread, then that thread will encounter a "spurious wakeup" if it calls park().
I see, and can the same happen for Object.wait as well? I gather so from the documentation. On Feb 10, 2015, at 1:04 PM, David Holmes <david.holmes@oracle.com> wrote:
Oh I just realized/remembered why we use Unsafe for this - it is because of the potential for intrinsics.
I can certainly imagine it's convenient place to put things in that regard. Paul.
On 10 Feb 2015, at 12:46, Paul Sandoz <paul.sandoz@oracle.com> wrote:
Hi David,
On Feb 10, 2015, at 1:02 PM, David Holmes <david.holmes@oracle.com> wrote:
Hi Paul,
When we added j.u.c there was reluctance to add these methods to Thread - this was the normal policy (for the time) of don't touch the core classes. So LockSupport is the public API and Unsafe was chosen as the implementation as it is a de-facto interface to the VM from JDK code rather then defining explicit native methods (I must admit I'm unsure why we went this route rather than simply hooking into jvm.cpp with JVM_park/JVM_unpark. I think in many ways it was/is just easier to call an Unsafe method and define a new unsafe.cpp native call. Plus we had a bunch of other Unsafe API's being used from j.u.c.)
So we can't just move things from LockSupport to Thread as we'd need to deprecate first etc etc.
I was thinking that the implementation of LockSupport could be updated to use any new stuff we could add to java.lang.{*, Thread}.
I am trying to tease apart the internal dependencies that 166 classes have on the platform. In the case of LockSupport there are two, Unsafe and Thread.
Adding native methods to 166 classes will introduce another form of dependency on the platform that i would prefer to avoid.
Right. And I suspect that the separate distributable of 166, outside of the Java Platform, would not want to have to carry a separate platform specific native library.
But I don't see any reason why we couldn't move the implementation from unsafe.cpp to jvm.cpp and invoke via a native method implementation of LockSupport. It would still be just as "unsafe" of course.
Can you think of any reasons, beyond that of "don't touch the core classes", why we cannot copy this functionality over to java.lang.{*, Thread} ?
Would you be thinking of making the changes public, i.e. new standard API on java.lang.Thread ? -Chris.
Aside: this is where the infamous "spurious wakeup" from park() can arise. If you just randomly unpark() a Thread there is nothing to guarantee that the thread doesn't terminate and free its native resources while you are working on it. But the ParkEvents are type-stable-memory, so even if the event has been disassociated from the target thread you can still call unpark() as it is never freed. However if that ParkEvent has since been reused by another thread, then that thread will encounter a "spurious wakeup" if it calls park().
I see, and can the same happen for Object.wait as well? I gather so from the documentation.
On Feb 10, 2015, at 1:04 PM, David Holmes <david.holmes@oracle.com> wrote:
Oh I just realized/remembered why we use Unsafe for this - it is because of the potential for intrinsics.
I can certainly imagine it's convenient place to put things in that regard.
Paul.
On Feb 10, 2015, at 3:39 PM, Chris Hegarty <chris.hegarty@oracle.com> wrote:
Adding native methods to 166 classes will introduce another form of dependency on the platform that i would prefer to avoid.
Right. And I suspect that the separate distributable of 166, outside of the Java Platform, would not want to have to carry a separate platform specific native library.
Yes.
But I don't see any reason why we couldn't move the implementation from unsafe.cpp to jvm.cpp and invoke via a native method implementation of LockSupport. It would still be just as "unsafe" of course.
Can you think of any reasons, beyond that of "don't touch the core classes", why we cannot copy this functionality over to java.lang.{*, Thread} ?
Would you be thinking of making the changes public, i.e. new standard API on java.lang.Thread ?
Yes, j.l.Thread seems like the ideal location :-) Paul.
Adding Doug Lea. On 11/02/2015 12:51 AM, Paul Sandoz wrote:
On Feb 10, 2015, at 3:39 PM, Chris Hegarty <chris.hegarty@oracle.com> wrote:
Adding native methods to 166 classes will introduce another form of dependency on the platform that i would prefer to avoid.
Right. And I suspect that the separate distributable of 166, outside of the Java Platform, would not want to have to carry a separate platform specific native library.
Yes.
Right and for that reason jsr166 distribution would not want to have to know whether to use Thread or Unsafe.
But I don't see any reason why we couldn't move the implementation from unsafe.cpp to jvm.cpp and invoke via a native method implementation of LockSupport. It would still be just as "unsafe" of course.
Can you think of any reasons, beyond that of "don't touch the core classes", why we cannot copy this functionality over to java.lang.{*, Thread} ?
Would you be thinking of making the changes public, i.e. new standard API on java.lang.Thread ?
Yes, j.l.Thread seems like the ideal location :-)
I don't see any point in moving it to Thread now. The public supported API already exists in LockSupport. As I said you'd have to deprecate it in 9 with an intent to remove in 10 - assuming you are even allowed to do that. The issue is not LockSupport versus Thread, but the use of Unsafe. David
Paul.
This time really adding Doug Lea :) On 11/02/2015 11:43 AM, David Holmes wrote:
Adding Doug Lea.
On 11/02/2015 12:51 AM, Paul Sandoz wrote:
On Feb 10, 2015, at 3:39 PM, Chris Hegarty <chris.hegarty@oracle.com> wrote:
Adding native methods to 166 classes will introduce another form of dependency on the platform that i would prefer to avoid.
Right. And I suspect that the separate distributable of 166, outside of the Java Platform, would not want to have to carry a separate platform specific native library.
Yes.
Right and for that reason jsr166 distribution would not want to have to know whether to use Thread or Unsafe.
But I don't see any reason why we couldn't move the implementation from unsafe.cpp to jvm.cpp and invoke via a native method implementation of LockSupport. It would still be just as "unsafe" of course.
Can you think of any reasons, beyond that of "don't touch the core classes", why we cannot copy this functionality over to java.lang.{*, Thread} ?
Would you be thinking of making the changes public, i.e. new standard API on java.lang.Thread ?
Yes, j.l.Thread seems like the ideal location :-)
I don't see any point in moving it to Thread now. The public supported API already exists in LockSupport. As I said you'd have to deprecate it in 9 with an intent to remove in 10 - assuming you are even allowed to do that.
The issue is not LockSupport versus Thread, but the use of Unsafe.
David
Paul.
On 02/10/2015 08:46 PM, David Holmes wrote:
This time really adding Doug Lea :)
I don't have very strong opinions about this. Placing park/unpark in Thread was our initial (circa 2000) proposal, so in that sense it's ideal, and in principle easily done by relaying LockSupport.{park/unpark} to Thread. But we have over time also exploited the current setup in a couple of cases to independently deal with Unsafe access to park and parkBlockers. These can be changed, although doing so while remaining performance-neutral will take some thought. (Which is similar to all the other cases where we'd like to replace Unsafe usages with VarHandles etc. I'm trying to keep up the attitude that this is not merely a nuisance, but an opportunity to revisit and improve implementations :-) Logistically, we'll somehow cope: At some point our main 166 sources will need to be split into jdk8 vs jdk9 versions. -Doug
On 11/02/2015 11:43 AM, David Holmes wrote:
Adding Doug Lea.
On 11/02/2015 12:51 AM, Paul Sandoz wrote:
On Feb 10, 2015, at 3:39 PM, Chris Hegarty <chris.hegarty@oracle.com> wrote:
Adding native methods to 166 classes will introduce another form of dependency on the platform that i would prefer to avoid.
Right. And I suspect that the separate distributable of 166, outside of the Java Platform, would not want to have to carry a separate platform specific native library.
Yes.
Right and for that reason jsr166 distribution would not want to have to know whether to use Thread or Unsafe.
But I don't see any reason why we couldn't move the implementation from unsafe.cpp to jvm.cpp and invoke via a native method implementation of LockSupport. It would still be just as "unsafe" of course.
Can you think of any reasons, beyond that of "don't touch the core classes", why we cannot copy this functionality over to java.lang.{*, Thread} ?
Would you be thinking of making the changes public, i.e. new standard API on java.lang.Thread ?
Yes, j.l.Thread seems like the ideal location :-)
I don't see any point in moving it to Thread now. The public supported API already exists in LockSupport. As I said you'd have to deprecate it in 9 with an intent to remove in 10 - assuming you are even allowed to do that.
The issue is not LockSupport versus Thread, but the use of Unsafe.
David
Paul.
On Feb 11, 2015, at 2:43 AM, David Holmes <david.holmes@oracle.com> wrote:
Adding Doug Lea.
On 11/02/2015 12:51 AM, Paul Sandoz wrote:
On Feb 10, 2015, at 3:39 PM, Chris Hegarty <chris.hegarty@oracle.com> wrote:
Adding native methods to 166 classes will introduce another form of dependency on the platform that i would prefer to avoid.
Right. And I suspect that the separate distributable of 166, outside of the Java Platform, would not want to have to carry a separate platform specific native library.
Yes.
Right and for that reason jsr166 distribution would not want to have to know whether to use Thread or Unsafe.
And that's why it should just be the former for the Java 9 platform and beyond. The general strategy is to reduce dependency on Unsafe, including for 166 classes. The VarHandles effort is part of that strategy to replace Unsafe enhanced access with a public alternative that is safe and just as performant.
But I don't see any reason why we couldn't move the implementation from unsafe.cpp to jvm.cpp and invoke via a native method implementation of LockSupport. It would still be just as "unsafe" of course.
Can you think of any reasons, beyond that of "don't touch the core classes", why we cannot copy this functionality over to java.lang.{*, Thread} ?
Would you be thinking of making the changes public, i.e. new standard API on java.lang.Thread ?
Yes, j.l.Thread seems like the ideal location :-)
I don't see any point in moving it to Thread now. The public supported API already exists in LockSupport.
Yes, but as i said the point is to tease apart the internal dependencies between the platform and LockSupport class. (A simple solution is to copy and rename this class to java.lang.ThreadSupport :-) .)
The issue is not LockSupport versus Thread, but the use of Unsafe.
It's because LockSupport uses Unsafe to access non-public fields of Thread, and i also want to break that internal dependency. I presume that LockSupport was created because agreement was not reached to add such core *thread*-based functionality to Thread. I dunno why such agreement was not reached, but so far i am not hearing any compelling technical reasons. Paul. <snip>
As I said you'd have to deprecate it in 9 with an intent to remove in 10 - assuming you are even allowed to do that.
Opinions differ but i think we should be more serious about removing stuff that has been marked deprecated for one major release if the intent to do so is made clear when deprecating.
Paul, I appreciate the issue with discontinuing use of Unsafe but this churn to the public APIs seems unwarranted. Would we have done it differently from day one? Sure. Does that mean we should change it all now? Not without a very good reason. And I'm on the fence there. The fact that LockSupport needs access to Thread internals is something that modules could actually resolve :) - though I'm not up to date on the interaction of module access and package access. Let's see what Doug thinks of all this too. Cheers, David On 11/02/2015 6:52 PM, Paul Sandoz wrote:
On Feb 11, 2015, at 2:43 AM, David Holmes <david.holmes@oracle.com> wrote:
Adding Doug Lea.
On 11/02/2015 12:51 AM, Paul Sandoz wrote:
On Feb 10, 2015, at 3:39 PM, Chris Hegarty <chris.hegarty@oracle.com> wrote:
Adding native methods to 166 classes will introduce another form of dependency on the platform that i would prefer to avoid.
Right. And I suspect that the separate distributable of 166, outside of the Java Platform, would not want to have to carry a separate platform specific native library.
Yes.
Right and for that reason jsr166 distribution would not want to have to know whether to use Thread or Unsafe.
And that's why it should just be the former for the Java 9 platform and beyond.
The general strategy is to reduce dependency on Unsafe, including for 166 classes. The VarHandles effort is part of that strategy to replace Unsafe enhanced access with a public alternative that is safe and just as performant.
But I don't see any reason why we couldn't move the implementation from unsafe.cpp to jvm.cpp and invoke via a native method implementation of LockSupport. It would still be just as "unsafe" of course.
Can you think of any reasons, beyond that of "don't touch the core classes", why we cannot copy this functionality over to java.lang.{*, Thread} ?
Would you be thinking of making the changes public, i.e. new standard API on java.lang.Thread ?
Yes, j.l.Thread seems like the ideal location :-)
I don't see any point in moving it to Thread now. The public supported API already exists in LockSupport.
Yes, but as i said the point is to tease apart the internal dependencies between the platform and LockSupport class. (A simple solution is to copy and rename this class to java.lang.ThreadSupport :-) .)
The issue is not LockSupport versus Thread, but the use of Unsafe.
It's because LockSupport uses Unsafe to access non-public fields of Thread, and i also want to break that internal dependency.
I presume that LockSupport was created because agreement was not reached to add such core *thread*-based functionality to Thread. I dunno why such agreement was not reached, but so far i am not hearing any compelling technical reasons.
Paul.
<snip>
As I said you'd have to deprecate it in 9 with an intent to remove in 10 - assuming you are even allowed to do that.
Opinions differ but i think we should be more serious about removing stuff that has been marked deprecated for one major release if the intent to do so is made clear when deprecating.
On Feb 11, 2015, at 11:04 AM, David Holmes <david.holmes@oracle.com> wrote:
Paul,
I appreciate the issue with discontinuing use of Unsafe but this churn to the public APIs seems unwarranted. Would we have done it differently from day one? Sure. Does that mean we should change it all now? Not without a very good reason. And I'm on the fence there.
Fair enough, i am less conservative than yourself on this matter :-)
The fact that LockSupport needs access to Thread internals is something that modules could actually resolve :) - though I'm not up to date on the interaction of module access and package access.
In this case 166 is imported into the base module. We don't want modules sitting on top of the platform to depend on internal platform classes, ideally we want to reduce the internal coupling between platform modules (via the use of qualified exports), and ideally the less Unsafe usage within the base module the better. The particulars of 166 development and usage, in that it gets imported into the platform but also used on top of the platform, make this a tricky balancing act.
Let's see what Doug thinks of all this too.
Yes. Paul.
On 10/02/2015 10:46 PM, Paul Sandoz wrote:
Hi David,
On Feb 10, 2015, at 1:02 PM, David Holmes <david.holmes@oracle.com> wrote:
Hi Paul,
When we added j.u.c there was reluctance to add these methods to Thread - this was the normal policy (for the time) of don't touch the core classes. So LockSupport is the public API and Unsafe was chosen as the implementation as it is a de-facto interface to the VM from JDK code rather then defining explicit native methods (I must admit I'm unsure why we went this route rather than simply hooking into jvm.cpp with JVM_park/JVM_unpark. I think in many ways it was/is just easier to call an Unsafe method and define a new unsafe.cpp native call. Plus we had a bunch of other Unsafe API's being used from j.u.c.)
So we can't just move things from LockSupport to Thread as we'd need to deprecate first etc etc.
I was thinking that the implementation of LockSupport could be updated to use any new stuff we could add to java.lang.{*, Thread}.
I am trying to tease apart the internal dependencies that 166 classes have on the platform. In the case of LockSupport there are two, Unsafe and Thread.
Adding native methods to 166 classes will introduce another form of dependency on the platform that i would prefer to avoid.
But I don't see any reason why we couldn't move the implementation from unsafe.cpp to jvm.cpp and invoke via a native method implementation of LockSupport. It would still be just as "unsafe" of course.
Can you think of any reasons, beyond that of "don't touch the core classes", why we cannot copy this functionality over to java.lang.{*, Thread} ?
Aside: this is where the infamous "spurious wakeup" from park() can arise. If you just randomly unpark() a Thread there is nothing to guarantee that the thread doesn't terminate and free its native resources while you are working on it. But the ParkEvents are type-stable-memory, so even if the event has been disassociated from the target thread you can still call unpark() as it is never freed. However if that ParkEvent has since been reused by another thread, then that thread will encounter a "spurious wakeup" if it calls park().
I see, and can the same happen for Object.wait as well? I gather so from the documentation.
Spec allows for it but it can't happen for the same reason as unpark() as it is based on Object monitors which can't vanish while in use. David
On Feb 10, 2015, at 1:04 PM, David Holmes <david.holmes@oracle.com> wrote:
Oh I just realized/remembered why we use Unsafe for this - it is because of the potential for intrinsics.
I can certainly imagine it's convenient place to put things in that regard.
Paul.
participants (4)
-
Chris Hegarty
-
David Holmes
-
Doug Lea
-
Paul Sandoz