RFR: 8188858: Caching latestUserDefinedLoader() results in ObjectInputStream.readObject()
Peter Levart
peter.levart at gmail.com
Mon Oct 16 09:02:05 UTC 2017
Hi Ogata,
I think that webrev.02 is safe as you describe. But there's one case
which now has some overhead. It's a common practice to subclass
ObjectInputStream and override resloveClass() method and implement
custom resolving (without calling super.resolveClass()). In such case,
the cached loader is unnecessarily set-up and then not used. So I'm
thinking about lazy caching.
For example:
- let public readObject() / readUnshared() entry and exit points just
clear the cached loader (set it to null).
- let resloveClass() do something like the following at entry:
CachedLoader cl = cachedLoader;
Thread curThread = Thread.currentThread();
ClassLoader loader;
if (cl == null) {
loader = latestUserDefinedLoader();
cl = new CachedLoader(loader, curThread);
} else if (cl.thread == curThread) {
loader = cl.loader;
} else {
// multi threaded use
loader = latestUserDefinedLoader();
}
// and then...
return Class.forName(name, false, loader);
What do you think?
Regards, Peter
On 10/13/2017 02:36 PM, Kazunori Ogata wrote:
> Hi Alan,
>
> Alan Bateman <Alan.Bateman at oracle.com> wrote on 2017/10/12 22:17:48:
>
>> This is better but it still not safe. You'll have to atomically set/get
>> the cachedLoader or put it into a thread local to ensure that
>> resolveClass picks up the loader cached by the current thread. A thread
>> local could work too although (needs study) it might need a reference to
>> the OIS to guard against nested deserialization with a different stream.
> Thank you for your review. I fixed the code that does not read the
> cachedLoader atomically when the code tries to update it.
>
> Updated webrev: http://cr.openjdk.java.net/~horii/8188858/webrev.02/
>
>
> The updated code does not use atomic CAS or ThreadLocal. This code can
> race when the cachedLoader is null, but I think it works correctly because
> a pair of a thread and a class loader (stored in a CachedLoader) is always
> correct regardless of the value of the cachedLoader field, and the thread
> that writes the cachedLoader last resets it to null. The thread that
> failed to cache a loader simply calls latestUserDefinedLoader(), which is
> the same behavior as the original code.
>
> Considering that multi-thread use of an OIS is rare, I don't want to add
> an overhead of CAS to update the cachedLoader, especially on the POWER
> platform because CAS has high overhead. Caching loaders in a ThreadLocal
> in each OIS can be more thread safe, but I'm not sure if its memory
> overhead is worth doing so for the rare (and correctly working) case.
>
>
> Regards,
> Ogata
>
More information about the core-libs-dev
mailing list