Developers with Java experience may have previously used ThreadLocal to store/read data isolated to a specific system user or user request. One common example is working with legacy servlet containers when each user request was allocated a single thread for an entire request/response roundtrip.
ThreadLocal's have never been a very good solution for any JVM application - they pass parameters without actually passing parameters to save on a little bit of boiler plate. They make code harder to test, since the ThreadLocal context must be set up. They also undermine the type system, since they make it impossible to know whether its safe to invoke a method or not, since the signature of that method does not say what ThreadLocals it takes.
ThreadLocals don't fit with Reactive Programming and Play is built on this model. The reason for this is that Reactive application code is asynchronous and hops around between lots of different threads. There is no guarantee which thread portions of your code will run in. For example, in Play the thread that accepts a request may not be the same thread that makes calls to external services or serves the corresponding response. Java 8 in general has the same problem, for example using the Java 8 streams API, which does its operations in parallel on other threads, cannot be used safely with code that depends on ThreadLocals.
Fortunately Play has better functionality to help you store data that is isolated and available to a specific request, session, or for the next user request only (Flash). Here are a few helpful links: