2009-05-03 5 views
2

J'ai un doute général concernant la publication des données et des changements de données entre les threads. Considérons par exemple la classe suivante.La visibilité des objets sur les threads

public class DataRace { 
    static int a = 0; 

    public static void main() { 
    new MyThread().start(); 
    a = 1; 
    } 

    public static class MyThread extends Thread { 
    public void run() { 
     // Access a, b. 
    } 
    } 
} 

Nous allons nous concentrer sur main().

Il est clair que

new MyThread().start(); 
a = 1; 

Il nous changeons la variable partagée un après l'MyThread est démarré et ne peuvent donc pas être une publication de thread-safe.

a = 1; 
new MyThread().start(); 

Mais cette fois le changement dans une est en toute sécurité publié à travers le nouveau fil, depuis Java Language Specification (JLS) garantit que toutes les variables qui étaient visibles à un fil A quand il démarre un thread B sont visibles pour le fil B, qui est effectivement comme avoir une synchronisation implicite dans Thread.start().

new MyThread().start(); 
int b = 1; 

Dans ce cas, lorsqu'une nouvelle variable est allouée après que les deux fils ont été donné naissance, est-il une garantie que que la nouvelle variable sera publié en toute sécurité à toutes les discussions. c'est-à-dire que si var b est accédé par l'autre thread, est-il garanti de voir sa valeur comme 1. Notez que je ne parle pas de modifications ultérieures de b après cela (qui doit certainement être synchronisé), mais la première allocation par le jvm.

Merci,

Répondre

0
a = 1; 
new MyThread().start(); 

L'affectation à « un » se déroulera avant le début est appelé le nouveau fil, de sorte que le nouveau thread imprime toujours la valeur « 1 »

new MyThread().start(); 
a = 1; 

En Dans ce cas, MyThread peut imprimer 1 ou 0 comme valeur de 'a'.

5

je n'étais pas pas tout à fait sûr de celui-ci:

a = 1; 
new MyThread().start(); 

... dans que je ne sais pas qu'il y avait aucune garantie que la valeur de a serait « rincée » à mémoire partagée le nouveau fil a commencé. Cependant, la spécification en parle explicitement. En section 17.4.4 il déclare:

Une action qui démarre un thread avec la synchronise première action dans le fil il commence.

(La discussion après montre essentiellement que ça va bien.)

Je ne sais pas ce que votre dernier exemple (avec b) est censé être au sujet. MyThread(). Start() démarre un nouveau thread qui s'exécute séparément.

+0

Lorsqu'une nouvelle variable est allouée après que les deux threads ont été générés, est-il garanti que la nouvelle variable sera publiée en toute sécurité sur tous les threads. c'est-à-dire si var b est accédé par l'autre thread, est-il garanti de voir sa valeur comme 1? – baskin

+0

Cela dépend vraiment de la situation exacte. Il doit y avoir quelque chose de spécifique pour garantir à la fois que le thread de lecture n'utilise pas une valeur mise en cache et que le thread d'écriture a publié l'écriture dans la mémoire partagée. Voir le chapitre 17 de la spécification référencée ci-dessus pour plus de détails (brain-busting). –

+0

"Rincé à la mémoire partagée"? (Faites-vous référence au tas?) Il n'y a aucun rinçage impliqué, car cela n'a rien à voir avec la sémantique du flux. L'affectation de valeur est atomique (avec une mise en garde mineure concernant les longs) dans la JVM. Après que a = 1 s'exécute, la variable : DataRace.a a la valeur de 1. Si un thread est engendré avant l'instruction a = 1, il n'y a aucune garantie quant à la valeur de DataRace.a qu'il verra. Il est certainement possible que le thread démarre et puis permute, et le thread principal s'exécute, et définit a = 1, puis l'autre thread verra un == 1. Il est plus probable qu'il verra a == 0. – alphazero

0

La déclaration de int b = 1 n'a rien à voir avec le thread que vous avez démarré. Il continue dans le fil principal.

La sécurité des threads est un problème si deux threads lisent ou muent le même objet en même temps, ou si deux threads obtiennent des verrous sur les ressources dans l'ordre inverse, de sorte que chacun attend l'autre (cela s'appelle impasse).

1

Je ne suis pas sûr de ce que vous demandez ici. I pense vous parlez de l'accès thread-safe à la "a" variable.

La question n'est pas l'ordre d'appel, mais le fait que

-accès à ne threadsafe. Ainsi, dans un exemple où plusieurs threads sont mis à jour et lus, vous ne pourrez jamais garantir que le "a" que vous lisez est la même valeur que celle que vous avez mise à jour (un autre thread peut avoir changé la valeur). -dans un environnement multithread, jvm ne garantit pas que les valeurs mises à jour pour a sont conservées en synchronisation. Par exemple.

Thread 1: a=1 

Thread 2: a=2 

Thread 1: print a <- may return 1 

Vous pouvez éviter cela en déclarant «volatile».

Comme il est écrit il n'y a aucune garantie sur la valeur de a.

BTW, est Josh Bloch Concurrency in Practicegrand livre sur ce sujet (et je dis que ne pas avoir obtenu tout au long encore;) - il m'a vraiment aidé à comprendre à quel point impliqué les questions de filetage peuvent obtenir.

+0

Java Language Specification (JLS) garantit que toutes les variables qui étaient visibles à un thread A lors du démarrage d'un thread B sont visibles à thread B. Ainsi l'ordre d'invocation aurait de l'importance ici? – baskin

+0

Concurrency in Practice est de Brian Goetz et al, Block a écrit Java et Java Puzzlers efficaces avec soit Pugh ou Gafter –

+0

@nonsequitor Juste pour être plus précis, Joshua Bloch est parmi les auteurs listés sur la couverture JCIP. –

0

J'ai mes doutes au sujet de cette question :)

Les questions relatives à l'accès à des ressources partagées entre les threads simultanés d'exécution est un sujet assez bien compris et étudié.

En général, si vous avez accès à une source avec une sémantique en lecture/écriture par une multiplicité de threads, vous devrez réguler l'accès à cette ressource. (Ici, la ressource est la variable de type int DataRace.a statique)

(je note également de +1 Steve B. ici que la question ici est pas l'ordre des invocations.)

0

Si b est local variable créée dans DataRace.main() comme l'indique l'extrait de code, elle n'est pas accessible à MyThread pour commencer, donc la question est discutable. Si b est une variable partagée entre le thread principal et le thread MyThread, elle n'a pas la visibilité correcte en l'absence d'une barrière de mémoire appropriée, MyThread peut donc ne pas voir la valeur correcte rapidement.