ThreadLocal's own get and initialValue methods are not synchronized. If the (sub) class you saw has them synchronized, there may be some additional code inside them that requires synchronization. Without seeing that code we won't be able to tell.
Each thread has its own value, true, but the get and initialValue method are both called on the one thread local object. That means that if the get and/or initialValue method accesses some of the state variables (other than the thread-to-value map), they still need synchronization.