La réponse de Hans Passant est bonne. Mais je me suis dit que j'allais essayer d'expliquer à un niveau un peu plus simple pour tous ceux qui rencontrent ce problème et qui sont novices en Java. Voilà
En Java, la mémoire est divisée en deux catégories : le tas et les piles. Le tas est l'endroit où vivent tous les objets et les piles sont l'endroit où les threads font leur travail. Chaque thread a sa propre pile et ne peut pas accéder aux piles des autres. Chaque thread a également un pointeur dans le code qui indique le bout de code qu'il est en train d'exécuter.
Lorsqu'un thread commence à exécuter une nouvelle méthode, il enregistre les arguments et les variables locales de cette méthode sur sa propre pile. Certaines de ces valeurs peuvent être des pointeurs vers des objets du tas. Si deux threads exécutent la même méthode au même moment, ils auront tous deux leurs pointeurs de code pointant vers cette méthode et auront leurs propres copies des arguments et des variables locales sur leurs piles. Ils n'interféreront l'un avec l'autre que si les éléments de leurs piles pointent vers les mêmes objets du tas. Dans ce cas, toutes sortes de choses peuvent se produire. Mais comme Hans le fait remarquer, les chaînes de caractères sont immuables (ne peuvent pas être modifiées), nous sommes donc en sécurité si c'est le seul objet "partagé".
De nombreux fils peuvent exécuter la même méthode. Ils peuvent ne pas être exécutés en même temps - cela dépend du nombre de cœurs dont dispose votre machine, car la JVM fait correspondre les threads Java aux threads du système d'exploitation, qui sont programmés sur les threads matériels. Vous n'avez donc que peu de contrôle sur la façon dont ces threads s'entrecroisent sans utiliser des outils complexes de gestion de l'exécution. synchronisation mécanismes.
Notez que le sommeil est quelque chose qu'un thread s'inflige à lui-même.