Generally, the thread-safety issue breaks down like this:
Local variables:
thread-safe in any context, servlet or otherwise
Instance variables:
not normally thread-safe, thread safe in servlets implementing the
SingleThreadedModel. But since as Corey mentions, most containers will
create multiple copies of your servlet (each with it’s own copy of the
instance variables) as simultaneous requests come in, instance variables
become essentially useless for sharing data outside the scope of a single
method call (the main reason they are used in servlets).
Static variables:
not thread-safe. Even the SingleThreadedModel does not help, since most
containers will again create several copies of your servlet to guarantee
acceptable performance, and those copies will all share the same static
variables associated with the servlet’s class, you must manually synchronize
access to them to be thread-safe.
Request scope attributes:
thread-safe by default, the container handles each request with a single
worker thread, even when it’s forwarded or included, the RequestDispatcher
interface takes care of marshalling the Request object safely. You have to
do strange things, like passing the request object out to an external
object, to be at risk here.
Session scope attributes:
not thread-safe. The user can open multiple browser windows, which under
some configurations will all share the same cookies (thus the same
HttpSession object on the server). Your page may also use frames, leading
to the same problem. Or impatient users may hit the refresh button on your
page, again same problem. Multiple accesses by simultaneous requests to the
same HttpSession object.
Context scope attributes:
not thread safe. All servlets in the webapp share these, so they’re clearly
at risk of frequent multi-threaded access.
access to any sort of common resource (like an open socket, a file on the
hard disk, etc.):
not thread-safe. Multiple requests coming in for any servlet that accesses
them can generate concurrent access.