ThreadLocal.getIfPresent()

classic Classic list List threaded Threaded
17 messages Options
Reply | Threaded
Open this post in threaded view
|

ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
Hello,

I thought I'd ask on this list, whether the following new method on
ThreadLocal class would be useful, desirable or undesirable:

     /**
      * Returns the value in the current thread's copy of this
      * thread-local variable.  If the variable has no value for the
      * current thread, null is returned and no value is initialized.
      *
      * @return the current thread's value of this thread-local or null
      */
     T getIfPresent()


Might event be:

     Optional<T> getIfPresent();



Thanks, Peter

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
On Wed, Jun 6, 2018 at 10:17 AM, Peter Levart via Concurrency-interest
<[hidden email]> wrote:
> Hello,
>
> I thought I'd ask on this list, whether the following new method on
> ThreadLocal class would be useful, desirable or undesirable:

I'd find it useful, but adding it (compatibly) would be very
difficult.  Classes which have overridden get() would have unexpected
behavior, etc.



--
- DML
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
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
[hidden email] wrote:
Hello,

I thought I'd ask on this list, whether the following new method on
ThreadLocal class would be useful, desirable or undesirable:
I'd find it useful, but adding it (compatibly) would be very
difficult.  Classes which have overridden get() would have unexpected
behavior, etc.


Are you thinking about possible "inconsistency" between overridden get() and not overridden getIfPresent() ? Like for example:


public class TenTimesThreadLocal extends ThreadLocal<Integer> {
    @Override
    public Integer get() {
        return super.get() == null ? null : super.get() * 10;
    }

    @Override
    public void set(Integer value) {
        super.set(value == null ? null : value / 10);
    }
}


Peter


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
On Wed, Jun 6, 2018 at 12:09 PM, Peter Levart <[hidden email]> 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
> <[hidden email]> 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;
    }
    // ...
}

--
- DML
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list


On 06/06/18 19:28, David Lloyd wrote:
On Wed, Jun 6, 2018 at 12:09 PM, Peter Levart [hidden email] 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
[hidden email] 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 list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
On Wed, Jun 6, 2018 at 1:17 PM, Peter Levart <[hidden email]> wrote:

> 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?

That would work assuming no ThreadLocal subclasses have such a method.
Adding an instance method to a class that can be subclassed is always
a risk in this way.

--
- DML
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
Hi,

Jumping into the conversation. isPresent would be useful and probably enough (better?).

Right now, if you want to mimic the ThreadLocalRandom (and the ConcurrentHashMap), you need to have access to the probe.
static final int getProbe() {
return UNSAFE.getInt(Thread.currentThread(), PROBE);
}
And it happened to me a bunch of time to need to know if there's something in a ThreadLocal without kicking its initialization. So isPresent would nice. Both can be useful, but isPresent is a must have. If can help mimicking code like this:

if ((h = ThreadLocalRandom.getProbe()) == 0) {
ThreadLocalRandom.localInit(); // force initialization
h = ThreadLocalRandom.getProbe();
wasUncontended = true;
}

Then... having access to the Probe would be nice too...

Henri

On 6 June 2018 at 14:17, Peter Levart via Concurrency-interest <[hidden email]> wrote:


On 06/06/18 19:28, David Lloyd wrote:
On Wed, Jun 6, 2018 at 12:09 PM, Peter Levart [hidden email] 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
[hidden email] 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 list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest



_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list

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.

-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 [hidden email] 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
[hidden email] 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 list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

-- 
-Nathan

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list


On 06/06/18 20:27, David Lloyd wrote:
On Wed, Jun 6, 2018 at 1:17 PM, Peter Levart [hidden email] wrote:
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?
That would work assuming no ThreadLocal subclasses have such a method.
Adding an instance method to a class that can be subclassed is always
a risk in this way.


I think the risk is not so big because ThreadLocal instances are typically not publicly exposed. They are usually encapsulated and code accessing them "knows" the semantics of the isPresent() method if such method exists in a subclass. There is a danger though that such method on an existing subclass is not public and not private which would break binary link-ability if such public method was added to ThreadLocal...

The risk can be avoided entirely with a static method taking a ThreadLocal instance. But static method is not so nice-looking when called... :-(



Peter


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
Conceptually, ThreadLocal is very Map-like and one can examine methods on Map to see whether they belong in ThreadLocal.
I recall being disappointed that remove() (added in 1.5) felt insufficient.
Something like isPresent could probably be used in ReentrantReadWriteLock.
You might want to try out any API change with ReentrantReadWriteLock.
Maybe we want the Map.compute* family of methods (except that the key is implicit Thread.currentThread())


On Wed, Jun 6, 2018 at 12:07 PM, Peter Levart via Concurrency-interest <[hidden email]> wrote:


On 06/06/18 20:27, David Lloyd wrote:
On Wed, Jun 6, 2018 at 1:17 PM, Peter Levart [hidden email] wrote:
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?
That would work assuming no ThreadLocal subclasses have such a method.
Adding an instance method to a class that can be subclassed is always
a risk in this way.


I think the risk is not so big because ThreadLocal instances are typically not publicly exposed. They are usually encapsulated and code accessing them "knows" the semantics of the isPresent() method if such method exists in a subclass. There is a danger though that such method on an existing subclass is not public and not private which would break binary link-ability if such public method was added to ThreadLocal...

The risk can be avoided entirely with a static method taking a ThreadLocal instance. But static method is not so nice-looking when called... :-(



Peter


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest



_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
On Thu, 7 Jun 2018 at 05:28, Peter Levart via Concurrency-interest <[hidden email]> wrote:
I think the risk is not so big because ThreadLocal instances are typically not publicly exposed. They are usually encapsulated and code accessing them "knows" the semantics of the isPresent() method if such method exists in a subclass. There is a danger though that such method on an existing subclass is not public and not private which would break binary link-ability if such public method was added to ThreadLocal...

So what you're saying is if, for example, a popular open source library uses ThreadLocal, it's likely to be an internal thing, and so the libraries public API would be completely unimpacted by changes to ThreadLocal. So, if there was a binary compatibility issue, that open source library would break with JDK X, but could easily fix it without breaking their own API. Is that right?

The risk can be avoided entirely with a static method taking a ThreadLocal instance. But static method is not so nice-looking when called... :-(



Peter

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


--
James Roper
Senior Developer, Office of the CTO

Lightbend – Build reactive apps!
Twitter: @jroper


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
On Thu, 7 Jun 2018 at 04:59, Nathan and Ila Reynolds via Concurrency-interest <[hidden email]> 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 [hidden email] 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
[hidden email] 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 list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

-- 
-Nathan
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


--
James Roper
Senior Developer, Office of the CTO

Lightbend – Build reactive apps!
Twitter: @jroper


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list


On 06/07/18 07:24, James Roper wrote:
On Thu, 7 Jun 2018 at 05:28, Peter Levart via Concurrency-interest <[hidden email]> wrote:
I think the risk is not so big because ThreadLocal instances are typically not publicly exposed. They are usually encapsulated and code accessing them "knows" the semantics of the isPresent() method if such method exists in a subclass. There is a danger though that such method on an existing subclass is not public and not private which would break binary link-ability if such public method was added to ThreadLocal...

So what you're saying is if, for example, a popular open source library uses ThreadLocal, it's likely to be an internal thing, and so the libraries public API would be completely unimpacted by changes to ThreadLocal. So, if there was a binary compatibility issue, that open source library would break with JDK X, but could easily fix it without breaking their own API. Is that right?

Yes, if that library doesn't expose the ThreadLocal API to the user directly, it could simply rename the conflicting method internally. Even if it does expose ThreadLocal API directly, there are four cases:

1 - It exposes a ThreadLocal subtype with public boolean isPresent() method: the users of that API are already aware of the semantics of that method - introducing ThreadLocal.isPresent does not break them
2 - It exposes a ThreadLocal type, but internally uses a subtype with public boolean isPresent() method: internal code is already aware of the semantics of that method - introducing ThreadLocal.isPresent does not break it
3 - It exposes a ThreadLocal subtype with public but override-incompatible isPresent() method (say: int isPresent()): this is binary compatible, but source incompatible. This is the only case with no easy way out as both the library and the clients of that library would have to be upgraded at the same time to be compiled with newer JDK.
4- It exposes a ThreadLocal type, but internally uses a subtype with override-incompatible or linkage-incompatible isPresent() method: the library can fix internal wiring without braking public API

So case 3 is the only really incompatible case. Which is highly unlikely, because of the java beans naming convention. A no-arg instance method called isXyz() typically has boolean return type.

Regards, Peter


The risk can be avoided entirely with a static method taking a ThreadLocal instance. But static method is not so nice-looking when called... :-(



Peter

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


--
James Roper
Senior Developer, Office of the CTO

Lightbend – Build reactive apps!
Twitter: @jroper



_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
Hi James,

On 06/07/18 07:36, James Roper via Concurrency-interest wrote:
On Thu, 7 Jun 2018 at 04:59, Nathan and Ila Reynolds via Concurrency-interest <[hidden email]> 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.

The problem with getIfPresent() returning null for ThreadLocal<Optional<X>> is it violates the convention that methods returning Optional<X> must never return null. So Optional<X> is not a good choice for the T in ThreadLocal<T>.


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

Those methods are most welcome in concurrent scenarios where they provide atomicity. In single-threaded scenarios they provide a kind of unification of Map vs. ConcurrentMap API which is good to be able to create common logic that works in both settings. ThreadLocal is not a Map and is never going to be a Map (as a subtype) and is always used in single-threaded scenarios, so compute* -like methods in ThreadLocal would just be an attempt to try to optimize a read-compute-write scenario so that it would involve a single hash-lookup operation. As compute- -like methods need lambdas and lambdas typically have to capture state, the optimization attempt might not be that effective.

But I agree that compute* (or maybe just compute(BinaryOperator)) is a viable alternative to getIfPresent() and/or isPresent() from purely functional standpoint. What I (and others) are trying to achieve is a way to "peek" into the state of ThreadLocal without actually triggering the initialization which might be heavy.

Adding compute to ThreadLocal would also provide another (the third) alternative way of associating a value with current thread:

1 - using get() in combination with initialValue()
2 - using set()
3 - using compute()

Is this good or does it complicate the API too much?

Regards, Peter


 

-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 [hidden email] 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
[hidden email] 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 list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

-- 
-Nathan
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


--
James Roper
Senior Developer, Office of the CTO

Lightbend – Build reactive apps!
Twitter: @jroper



_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list


On 06/07/18 10:02, Peter Levart wrote:
But I agree that compute* (or maybe just compute(BinaryOperator)) ....

Well, I meant to say compute(UnaryOperator<T>). That one and the following signature would also be useful:

public <P> T compute(P param, BiFunction<? super P, ? super T, ? extends T> computeFunction)

 ...which would allow passing parameter(s) to non-capturing lambda(s)...

Peter


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
In reply to this post by JSR166 Concurrency mailing list
On Thu, Jun 7, 2018 at 3:02 AM, Peter Levart via Concurrency-interest
<[hidden email]> wrote:
> The problem with getIfPresent() returning null for ThreadLocal<Optional<X>>
> is it violates the convention that methods returning Optional<X> must never
> return null. So Optional<X> is not a good choice for the T in
> ThreadLocal<T>.

+1 inasmuch as Optional is good for anything, it is definitely not
good for this.

> I also like Martin's ideas of introducing compute* methods similar to what
> Map offers.
>
> Those methods are most welcome in concurrent scenarios where they provide
> atomicity. In single-threaded scenarios they provide a kind of unification
> of Map vs. ConcurrentMap API which is good to be able to create common logic
> that works in both settings. ThreadLocal is not a Map and is never going to
> be a Map (as a subtype) and is always used in single-threaded scenarios, so
> compute* -like methods in ThreadLocal would just be an attempt to try to
> optimize a read-compute-write scenario so that it would involve a single
> hash-lookup operation. As compute- -like methods need lambdas and lambdas
> typically have to capture state, the optimization attempt might not be that
> effective.
>
> But I agree that compute* (or maybe just compute(BinaryOperator)) is a
> viable alternative to getIfPresent() and/or isPresent() from purely
> functional standpoint. What I (and others) are trying to achieve is a way to
> "peek" into the state of ThreadLocal without actually triggering the
> initialization which might be heavy.
>
> Adding compute to ThreadLocal would also provide another (the third)
> alternative way of associating a value with current thread:
>
> 1 - using get() in combination with initialValue()
> 2 - using set()
> 3 - using compute()
>
> Is this good or does it complicate the API too much?

The get() method can be overridden; what does this mean for the
semantics of compute()?  And what does compute() actually do with an
initial value?  Is the initial value constructed and supplied to the
compute() lambda or do we supply null in this case?

I think that any answer to any of these questions is going to be
unintuitive and/or annoying for _some_ use case or another.  Sticking
to isPresent(), get(), and set() keeps things simple and obvious, and
is probably save for the reasons you outlined above.  The double hash
lookup sucks, conceptually, but realistically won't all the relevant
info be very likely to be in L1 cache for the second lookup in most
cases?  I doubt it's a real problem other than being "itchy".

--
- DML
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ThreadLocal.getIfPresent()

JSR166 Concurrency mailing list
On Thu, Jun 7, 2018 at 12:47 PM, David Lloyd <[hidden email]> wrote:
> I think that any answer to any of these questions is going to be
> unintuitive and/or annoying for _some_ use case or another.

You know what would be _really_ nice?  Real thread-local fields, via
e.g. ACC_THREAD, which are managed by the JVM.  I bet the JVM could
come up with an index strategy that's better than a hash table lookup,
especially for static thread-local fields.

Hey, if they did it for C, why not for Java :)



--
- DML
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest