Thanks for the pointer. Looks like tables are indeed threadsafe. From your link -
"The hash-table-put! procedure is not atomic, but the table is protected by a lock."
As far as threadlocal goes... new-thread returns the thread descriptor and you can use that directly as a hash key.
arc> (= a (table))
#hash()
arc> (= (a (new-thread (fn () (sleep 10)))) 5)
5
arc> a
#hash((#<thread> . 5))
This is inconvenient by itself since in arc you can't access the current thread descriptor without some trickery. It seemed easiest to expose mzscheme's current-thread. I imagine that will have to end up in arc eventually.