Only setup exception from thread for joining when we have to

This makes it less prone to race conditions, because we only setup the
exception for use in Thread#join if we don't raise it directly because
of Thread.abort_on_exception. This ensures the exception doesn't get
raised twice due to race conditions.

We ensure the working by either setting up the @exception object before
marking the thread as not alive anymore, or delay raising the exception
into the main thread if we have shut down everything properly for this
thread.

Fixes #2259
Fix race condition in Thread spec
Use dirty object setup for String.from_codepoint
Fix last failing spec for Kernel#sprintf on 1.9