[concurrency-interest] ThreadLocal.getIfPresent()

James Roper james at lightbend.com
Thu Jun 7 01:36:03 EDT 2018

On Thu, 7 Jun 2018 at 04:59, Nathan and Ila Reynolds via
Concurrency-interest <concurrency-interest at cs.oswego.edu> wrote:

> I think isPresent() should be added no matter what is decided about
> getIfPresent().  This will allow for "null" being present in ThreadLocal
> and detecting it.  For example, think of a situation where if the value is
> not present, you want to do some expensive operation.  At the end of the
> operation, you decide that nothing should be stored in ThreadLocal, but you
> want to cache this decision and prevent the expensive operation from being
> done again.  Without isPresent(), then some dummy Object has to be stored
> in ThreadLocal.  I have never run into this situation while using
> ThreadLocal, but it is a situation I bump into in other class designs.
> As for getIfPresent(), I thought it was a good addition to the API.  I
> cannot think about a situation where I would have needed it.  If I did, I
> probably figured out some workaround.
Allowing for null to be considered a present value, such that isPresent()
returns true if you set a thread local to null, presents a big problem for
gitIfPresent(), since what can getIfPresent() return, that will allow
distinguishing between a present null, and a non present value? If it
returns T, then it will return null for both present nulls, and no value.
If it returns Optional<T>, then there's no way for it to return a present
null, since Optional cannot contain null. You'd need Optional<Optional<T>>
to correctly distinguish between a present value, and a null.

But, Optional also offers a good solution to this without introducing
isPresent. You can encode a present empty value into a thread local today
by using ThreadLocal<Optional<T>>, and setting it to Optional.empty. This
makes the programming logic much cleaner, as it makes it clear that this
thread local is not just storing cached values, it's storing cached empty
values too, making it much easier to avoid programming mistakes when
working with it. And of course, this is the entire reason for introducing
an Optional type in the first place, it allows you to encode the
presentness or lack thereof into the type system, instead of having to add
special purpose methods like isPresent everywhere where you have a
container that may need to indicate whether a value is present or not.

So I actually think that isPresent() isn't as useful, since for the use
cases you describe using ThreadLocal<Optional<T>> is a better design in the
first place, but Optional<T> getIfPresent() does have value as a
convenience for when null means is not present. In an ideal world, we'd
change get() to return Optional<T>, and then everything would be completely
explicit, there's never any nulls, but of course we can't do that due to
backwards compatibility.

I also like Martin's ideas of introducing compute* methods similar to what
Map offers.

> -Nathan
> On 6/6/2018 12:17 PM, Peter Levart via Concurrency-interest wrote:
> On 06/06/18 19:28, David Lloyd wrote:
> On Wed, Jun 6, 2018 at 12:09 PM, Peter Levart <peter.levart at gmail.com> <peter.levart at gmail.com> wrote:
> Di David,
> On 06/06/18 18:48, David Lloyd wrote:
> On Wed, Jun 6, 2018 at 10:17 AM, Peter Levart via Concurrency-interest<concurrency-interest at cs.oswego.edu> <concurrency-interest at cs.oswego.edu> wrote:
> Are you thinking about possible "inconsistency" between overridden get() and
> not overridden getIfPresent() ? Like for example:
> Exactly.  You could possibly get around the issue by declaring it like this:
> public class ThreadLocal<T> {
>     // ...
>     public static <T> T getIfPresent(ThreadLocal<T> tl) {
>         return Thread.currentThread().hasThreadLocalInternal(tl) ?
> tl.get() : null;
>     }
>     // ...
> }
> Or there could simply be the following method in ThreadLocal:
> /**
>  * @return true if current thread has a value present for this
> thread-local variable; false if not.
>  */
> public boolean isPresent()
> Would that be preferable?
> Peter
> _______________________________________________
> Concurrency-interest mailing listConcurrency-interest at cs.oswego.eduhttp://cs.oswego.edu/mailman/listinfo/concurrency-interest
> --
> -Nathan
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

*James Roper*
*Senior Developer, Office of the CTO*

Lightbend <https://www.lightbend.com/> – Build reactive apps!
Twitter: @jroper <https://twitter.com/jroper>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20180607/b2eda3b8/attachment-0001.html>

More information about the Concurrency-interest mailing list