0

J'ai 4 threads essayant chacun de trouver la valeur max dans une liste liée.Pourquoi ai-je besoin de synchroniser cette variable?

C'est ma classe de fil:

public class MyThread extends Thread { 

    LinkedList<Integer> list; 
    int max = Integer.MIN_VALUE; 

    public MyThread(LinkedList<Integer> list) { 
     this.list = list; 
    } 

    public void run() { 
     synchronized (list) {  /* If I don't synchronize list, I get a NoSuchElementException at list.remove() */ 
      while (!list.isEmpty()) { 
       int num = list.remove(); 

       if (num > max) { 
        max = num; 
       } 
      } 
     } 
    } 
} 

Et voici la classe avec la méthode principale:

public class Application { 

    public static void main(String args[]) throws InterruptedException { 
     LinkedList<Integer> list = new LinkedList<Integer>(); 

     for (int i = 0; i < 10; i++) { 
      list.add(i); 
     } 

     MyThread t1 = new MyThread(list); 
     MyThread t2 = new MyThread(list); 
     MyThread t3 = new MyThread(list); 
     MyThread t4 = new MyThread(list); 

     t1.start(); 
     t2.start(); 
     t3.start(); 
     t4.start(); 

     t1.join(); 
     t2.join(); 
     t3.join(); 
     t4.join(); 

     System.out.println(t1.max); 
     System.out.println(t2.max); 
     System.out.println(t3.max); 
     System.out.println(t4.max); 
    } 
} 

Dans le code ci-dessus, je dois synchroniser la variable list dans la méthode d'exécution ou sinon je vais obtenir un NoSuchElementException à list.remove(). pourquoi est-ce le cas? Chaque thread ne possède-t-il pas sa propre liste, donc il n'y a pas d'interférence de thread?

Merci

+0

Chaque constructeur 'MyThread' est appelé avec la même référence de liste, donc tous les threads utiliseront la même liste. – korolar

+2

Étant donné que vous passez la 'List' dans chaque' Thread', pourquoi croiriez-vous que chacun a sa propre copie? –

+0

[Lire la Javadoc] (https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html), en particulier le bit en gras qui indique "** Notez que cette implémentation n'est pas synchronisé. ** ". –

Répondre

1

Je vais aborder une autre partie de votre question qui @Rishi adressée:

t-il pas chaque thread a sa propre liste donc il n'y a pas d'interférence de fil?

La réponse simple est: Non, ce n'est pas le cas. En Java, lorsque vous passez un objet de type classe à un constructeur ou une méthode, vous ne passez pas l'obejct lui-même, mais plutôt un pointeur vers lui. Si vous souhaitez transmettre une copie distincte de la liste liée à chaque thread, vous devez utiliser LinkedList#Clone.

Si vous utilisez clone, lorsqu'un thread supprime un entier de sa liste liée, il ne sera pas supprimé des autres listes liées. Pour correctement paraléliser cela, vous devez utiliser un tableau standard avec tous vos nombres et affecter un segment de ce tableau à chaque thread (par exemple, le thread 1 fait 0-9, thread 2 fait 10-19, thread 3 fait 20-29, etc.). Le contenu du tableau sera visible à tous les threads créés après le dépôt du contenu dans le tableau.


Je devrais également noter que vous ne devriez pas étendre le fil. Au lieu de cela, étendez Runnable et passez-le à un thread. En outre, un tableau (liste) serait mieux que 4 variables distinctes car il vous permet de modifier facilement le nombre de threads plus tard.

1

LinkedList n'est pas adapté aux threads. Il faudrait donc une synchronisation externe si vous opérez sur LinkedList avec plus d'un thread.

Vous pouvez utiliser BlockingQueue, dont la méthode poll() serait utile dans ce cas.

+0

Ce n'est pas tout à fait juste que ce n'est pas sûr pour les threads: c'est que les 'isEmpty()' et hasNext() 'ne sont pas exécutés atomiquement, c'est-à-dire qu'un autre thread peut entrer et voler l'élément qui a causé' isEmpty() 'pour retourner false. +1 pour 'BlockingQueue'. –