Locks become more relevant. Old java you might have limited concurrency using thread pool size. With virtual threads something like a blocking queue or semaphore is likely a better choice.
Reactive java should be avoided (IMO). It was a decent choice for old java, for virtual thread java you get little benefits from it.
This will probably change, but with old java `synchronized` was alright. Virtual thread java you want to avoid that.
This likely won't change, ThreadLocalStorage is a bad idea with virtual threads, you almost certainly want to use ScopedValues instead.
You should understand the implications of structured concurrency. It's not fully ready yet, but at very least the `try(var service = newVirtualThreadPoolExecutor)` does work (I believe) which will block until all tasks launched are completed. This is likely desirable but might be unexpected if you wanted to fire and forget something.
Otherwise, I think all the old concurrency advice applies.