The alternatives are either (a) avoiding shared state; (b) strong lifetime management such that you make sure one parent thread owns all of the data that its child threads are going to use; (c) concurrent GC; (d) pretending it's not a problem like Go does and doing stop-the-world GC.
Thanks again folks!
Interesting point about the cache invalidation, though. I wonder if we'll see chip vendors going out of their way to improve performance and invalidation when using atomic ops.
They already put a lot of effort into making this stuff as efficient as possible - the fact that Intel is going in the direction of hardware transactional memory indicates to me that they don't think the bus locking/cache snooping approach scales, and I can't say I'm surprised.
Reference counting is also not even that great for shared memory multithreading. The (atomic) increment/decrement operations typically cause lots of cache invalidation, so you'll get a slowdown even for immutable objects.