You haven's show how you are doing multi-threading, so I can only guess what you have done:
In YourService.doSomething(), it createThreads. For each thread, it is doing DB related actions. Is that right?
As desecribed in another answer, transaction context is stored in thread local manner. Therefore, your logic in thread has no association with any transaction. One thing you can verify this is, apart from the logics in threads, in doSomething() you also do some DB actions. You will find that db actions you performed in doSomething() is committed while actions in threads are lost.
One of the reasonable way to solve is, normally we have a layer of application service which serves as a unit-of-work, and hence, we have transaction boundary on it (similar to your Service). Your thread should invoke the operations provided by the service. Of course, they will be all in different transaction.
If you want them all in one transaction, another way is, instead of let individual thread do the DB action, threads now do the heavy work and post the result back to the originated thread (by a producer-consumer queue for example). The originated thread is responsible to gather the result and perform DB actions.
Personally I would try to avoid manually passing the transaction context around different thread. This is simply ruining the whole idea of declarative transaction.