2009-07-16 4 views
2

Je rencontre des problèmes avec Synchronisé ne se comporte pas la façon dont je pense, j'ai essayé d'utiliser mot-clé volatile aussi:java émission synchronisée

Shared Object:


public class ThreadValue { 
private String caller; 
private String value; 
public ThreadValue(String caller, String value) { 
    this.value = value; 
    this.caller = caller; 
} 

public synchronized String getValue() { 
    return this.caller + "  " + this.value; 
} 
public synchronized void setValue(String caller, String value) { 
    this.caller = caller; 
    this.value = value; 
} 
} 

Discussion 1:


class CongoThread implements Runnable { 
    private ThreadValue v; 
    public CongoThread(ThreadValue v) { 
    this.v = v; 

    } 
    public void run() { 
    for (int i = 0; i 10; i++) { 
    v.setValue("congo", "cool"); 
    v.getValue(); 
    } 
    } 
} 

Fil 2:


class LibyaThread implements Runnable { 
    private ThreadValue v; 
    public LibyaThread(ThreadValue v) { 
    this.v = v; 

    } 
    public void run() { 
    for (int i = 0; i 10; i++) { 
     v.setValue("libya", "awesome"); 
     System.out.println("In Libya Thread " + v.getValue()); 

    } 
    } 
} 

appel Classe:


class TwoThreadsTest { 
    public static void main (String args[]) { 

    ThreadValue v = new ThreadValue("", ""); 
     Thread congo = new Thread(new CongoThread(v)); 
     Thread libya = new Thread(new LibyaThread(v)); 

    libya.start(); 
     congo.start(); 

    } 
} 

De temps en temps que je reçois "en Libye discussion congo cool" qui ne devrait jamais arriver. Je m'attends seulement à: "En Libye Thread libya génial" "Dans le Congo Thread congo cool"

Je ne m'attends pas à être mélangés.

Répondre

5

Les appels peuvent entrelacer comme ce qui suit:

Thread 1 : v.setValue() 
Thread 2 : v.setValue() 
Thread 1 : v.getValue() // thread 1 sees thread 2's value 
Thread 2 : v.getValue() // thread 2 sees thread 2's value 
3

Il pourrait être dans cet ordre il est donc correct:

v.setValue("libya", "awesome"); 
//context switch 
v.setValue("congo", "cool"); 
//context switch 
System.out.println("In Libya Thread " + v.getValue()); 

Par conséquent, vous avez une des conditions de course dans un sens. Synchronized acquiert un verrou chaque fois que vous essayez d'appeler la méthode synchronisée, vous avez donc besoin d'une autre façon d'impliquer l'accès synchronisé à la variable. Par exemple, vous pouvez supprimer synchronisé des méthodes et procédez comme suit:

public void run() 
{ 
    for (int i = 0; i 10; i++) 
    { 
    synchronized(v) 
    { 
     v.setValue("caller", "value"); 
     v.getValue(); 
    } 
    } 
} 
3

Les appels à getValue() et setValue() peuvent être intercalés. C'est-à-dire qu'aucun thread ne sera dans getValue() en même temps qu'un autre thread est dans getValue() ou setValue() et aucun thread ne sera dans setValue() alors qu'un autre thread est dans getValue() ou setValue(). Cependant, il n'y a aucune garantie qu'un seul thread fera des appels séquentiels à setValue() getValue() sans être préempté par un autre thread.

Fondamentalement, cela est parfaitement légal et possible:

Discussion 1: v.setValue()
autre thread (s): Un nombre quelconque de v.getValue() 's/v.setValue() 's
discussion 1: v.getValue()

4

Cela devrait vous obtenir le comportement que vous recherchez.

Discussion 1:

class CongoThread implements Runnable { 
    private ThreadValue v; 

    public CongoThread(ThreadValue v) { 
     this.v = v; 
    } 

    public void run() { 
     for (int i = 0; i < 10; i++) { 
      synchronized(v) { 
       v.setValue("congo", "cool"); 
       System.out.println("In Congo Thread " + v.getValue()); 
      } 
     } 
    } 
} 

Discussion 2:

class LibyaThread implements Runnable { 
    private ThreadValue v; 

    public LibyaThread(ThreadValue v) { 
     this.v = v; 
    } 

    public void run() { 
     for (int i = 0; i < 10; i++) { 
      synchronized(v) { 
       v.setValue("libya", "awesome"); 
       System.out.println("In Libya Thread " + v.getValue()); 
      } 
     } 
    } 
} 
+1

Dans un programme non trivial, vous voulez probablement cacher même ce niveau de synchronisation. Avoir une méthode comme setValueAndReturnString() qu'il a lui-même synchronisé.Vous ne voulez pas compter sur les appelants qui gèrent le multithreading correctement. – AngerClown

+0

D'accord. Je pensais simplement qu'en fournissant à Mo la version du code qui devrait atteindre le comportement qu'il cherchait, et avec la réponse que les autres ont fournie, cela l'aiderait à comprendre ce qui ne va pas et à mieux comprendre le fonctionnement de la synchronisation. –