9
votes

Comment pensez-vous et prédisez-vous la production d'une question de filetage comme celle-ci?

Je prépare le SCJP et la multithreading a été ma zone la plus shakieuse, principalement parce que je ne sais pas comment regarder du code multithreading et la promener. Jusqu'à présent, mon approche a été d'écrire en anglais ce qui pourrait se produire dans chaque fil et tester quelques cas avec des threads se croisant de manière aléatoire, ce qui est une approche vraiment frappante et fastidieuse. Je voudrais donc voir comment un professionnel irait à ce sujet. Seriez-vous prêt à lire le code ci-dessous (c'est la dernière question qui me donne des problèmes) et écrivez-vous ce qui se passe à travers votre tête (Stuff--------contre-Code uniquement, s'il vous plaît :) Lorsque vous travaillez les sorties possibles? Les choix qui viennent avec la question sont à la fin. Ce que je cherche n'est pas la solution, ce que j'ai, mais comment l'on arrive à la solution efficacement à l'examen.

et oui, je sais que cette question n'a pas de réponse précise, etc., etc. acceptée Le vote va à la réponse plus claire et la plus facile à imiter, d'accord :) p>

merci à tout le monde! p>

Question: laquelle de ces réponses sont des sorties possibles? P>

public class Threads1 {

    int x = 0;

    class Runner implements Runnable {

        public void run() {
            int current = 0;
            for (int i = 0; i < 4; i++) {
                current = x;
                System.out.print(current + ", ");
                x = current + 2;
            }
        }
    }

    public static void main(String[] args) {
        new Threads1().go();
    }

    public void go() {
        Runnable r1 = new Runner();
        new Thread(r1).start();
        new Thread(r1).start();
    }
}


7 commentaires

Alors, quelle est la réponse Anita? J'aimerais voir votre réponse avant de vous donner ma façon de penser au problème.


La visualisation est la clé, faites votre propre technique de diagramme, suffisamment pour montrer ce qui se passe simultanément et quelles ressources sont partagées entre chaque fil.


Je n'ai pas donné la réponse parce que ça serait trop facile :) Sérieusement, une fois que je connais la réponse, je peux expliquer pourquoi c'est juste, mais il incitent à savoir ce qu'il est en premier lieu de faire et de faire 't faire encore.


La vraie réponse à cette question est que c'est horrible, horrible codage multithread et quiconque produisant du code comme celui-ci dans un environnement de production devrait non seulement être immédiatement licencié, mais en fait interdit de la programmation toujours.


@kyoryu imagine que vous avez un code hérité du refacteur pour refacteur, allez-vous simplement dire à votre patron »Nah, c'est un morceau de code laid de dieu, ne veux pas le réparer. Laissez-moi vérifier à la place! 11". Les exercices de filetage SCJP ne sont pas si mauvais, en fait, vous pouvez en apprendre à peu près.


@kyoryu a comme l'ancienne question mathématique sur les trains qui se déroulent à différentes vitesses et que vous devez comprendre quand ils se passent, le point de la question et le test sont pas pour montrer le code de production. Sa montrer que vous avez une forte compréhension des concepts et la capacité de les appliquer. Démérifier cette sortie est un bon moyen de démontrer cela.


Non, je corrigerais le code. Je suis à peu près sûr que la réponse est A, C ici et l'écart déverrouillé entre la lecture de la valeur actuelle de x et la modifier est la raison. Et oui, je comprends le point de l'exercice. Mais si les gens s'habituent à voir un code multithreading comme celui-ci, ma peur serait qu'elle penserait que c'est un moyen approprié de l'écrire et d'utiliser les «astuces» qu'ils ont trouvé dans le code comme celui-ci. Si Junior Devs cherche un mauvais code comme un exercice, je veux vraiment qu'ils soient conscients que c'est un mauvais code à l'avance.


3 Réponses :


5
votes

Mon approche des problèmes multi-threads consiste à rompre le code que le fil s'exécutera puis de déterminer le nombre de threads exécutera ce code et si l'accès à toutes les variables que d'autres threads pouvaient potentiellement utiliser.

Dans l'exemple, il y a 3 threads. Le Appels de thread Nouveau threads1 (). Go (); , crée R1 et Démarre 2 threads, nouveau thread ( R1) .Start (); et nouveau thread (R1) .start (); . Maintenant que nous savons combien de threads nous pouvons suivre ce qu'ils vont faire.

Le fil principal va mourir après son retour de Go () .

Les 2 autres threads vont accéder à la méthode exécution () de l'objet objet , r1 . Maintenant, ce que nous savons aussi, c'est que chaque thread exécutera exécuter () . Permet de regarder ce que exécuter () fait. Il a une boucle pour qui imprime la sortie chaque fois qu'elle exécute la boucle. Par conséquent, l'appel à exécuté () imprimera 4 fois. Donc, 2 threads Chaque thread imprimera 4 fois. Par conséquent, la sortie ne peut avoir plus que 8 .

Concernant ce que ces chiffres seront ne seront pas vraiment possibles car l'instance coureur sera la même pour chaque thread la variable x peut changer en fonction de l'autre Fil qui appelle également exécuté () . Par conséquent, tout ce dont vous avez besoin pour déterminer est que la séquence de chiffres est-elle possible? La réponse à cette question est «oui» pour A et C. Cela est dû au fait que vous n'avez aucune idée lorsque chaque thread sera préempté par l'autre et, depuis lors, lors de la boucle, une copie locale est faite, vous pourriez obtenir des commandes très uniques.

Comme mentionné ci-dessous par SB, l'option B, même s'il a 8 sorties, il n'est pas possible. Essayez de proposer une séquence de fil pour créer cette sortie.


6 commentaires

Oh wow. C'est un bon appel. Ma faute. Je vais corriger ça. Superbe capture.


La réponse pourrait être A, B, ou même C en fonction de la priorité Chaque thread a et que chaque instruction est exécutée. Ma meilleure hypothèse serait de répondre à une seule réponse qui affiche certains numéros répétés entrelacés, ce qui signifie que les deux threads sont exécutés en parallèle. Mais l'un des 3 premiers pourrait être justifié.


@Yanick - Non, je pensais qu'au début aussi mais B n'est pas possible. Vous ne pouvez pas avoir 6 numéros de plus en plus, puis 2 augmenter, car cela signifierait que 1 thread a écrit au moins 5 fois.


@ Linuxuser27, oui, j'ai essayé de modifier mon commentaire, mais je ne pouvais pas. B n'est pas valide, car lorsque 2 est écho du deuxième fil, le nombre suivant doit être supérieur ou égal à 12 du premier fil


@Yanick - C'est un exemple classique que même après des années de travail multi-filetés, vous pouvez toujours regarder la sortie "potentiel" et faire une erreur. Nous sommes en bonne compagnie que je suppose :)


@ Linuxuser27, Eh bien, il s'agit d'une queue classique d'un qui fait plus d'une chose à la fois et de ne pas accroître l'attention sur la question :) l'erreur est humaine. Si je faisais cet essai, j'aurais très probablement revu la question et la corrigera.



11
votes

a et c (en supposant que la question est laquelle de ces réponses sont des sorties possibles? )

La partie difficile, bien sûr, n'est pas quand vous trouvez une solution possible. Mais plutôt, il est préférable de croire à celles que vous pensez être pas possible et essayez de vous convaincre que vous avez une raison solide pour laquelle ce n'est pas possible et que vous "J'ai éliminé tous les moyens de contourner votre raison.

Jusqu'à présent, mon approche a été d'écrire en anglais ce qui pourrait se passer dans chaque thread ...

Vous devez déterminer quel fil imprimé chaque numéro. Vous trouverez ci-dessous le format de succion le plus efficace et le plus efficace que je puisse penser que et faciliter la croix / effacer / effacer / écrire au fur et à mesure que vous travaillez grâce à des possibilités. Réaliser:

  • Une fois que vous avez trouvé une réponse possible déplacer sur . Peu importe que ce ne soit probablement pas probable dans le monde réel ou qu'il peut y avoir d'autres combinaisons possibles (ou impossibles). Tant que vous avez trouvé 1 possibilité, c'est tout ce dont vous avez besoin déplacer sur .

  • Essayez d'abord l'approche la plus simple, par ex. Supposez T1 pour chaque numéro jusqu'à ce que vous n'ayez pas atteint un nombre qui ne pouvait pas être T1, alors vous remplissez T2, et ainsi de suite .. Espérons que vous arrivez à la fin sans contradiction (ni contradiction faciles à résoudre). Une fois que vous avez trouvé une combinaison possible, passez à autre chose.

  • N'hésitez pas à passer à Éliminer les éventuels éventuels rapidement afin que vous puissiez vous concentrer sur les probablement impossibles.

    Voici la dernière modification de ma feuille de travail / feuille de calcul (annexé avec mes annotations mentales): xxx

    Remarque:

    http://download.oracle.com/javase/tutorial/essential/ Concurrence / Atomic.html

    • lit et écrit sont atomiques pour les variables de référence et pour la plupart des variables primitives (tous types, à l'exception du double et du double).
    • ...

      Les actions atomiques ne peuvent pas être entrelées, elles peuvent donc être utilisées sans crainte d'interférences de fil.


2 commentaires

@Bertf pouvons-nous penser comme si ceci: peu importe l'exécution des threads, il doit y avoir la plupart des numéros imprimés, de sorte que d et e ne peuvent pas être produits par cet exemple, puis pour utiliser vos pensées pour A, B et C?


On dirait droit à moi @xelian - votre approche éliminerait rapidement D et E.



0
votes

Cette question est beaucoup plus trompeuse qu'il n'y paraît - je l'aime, plus j'y pense. J'ai commencé ma réponse à parler de la façon dont je regarde les programmes de fil - j'analysez les points de synchronisation et les appels d'E / S. Mais cela n'en a aucun sauf pour l'imprimeur qui n'a pas de synchronisation interne. Nous sommes donc laissés au timing aléatoire (voir conditions de course ). Ceci combiné sans moyen garantie de synchroniser les valeurs de x entre les threads signifie qu'il sera aléatoire.

Cependant, si nous examinons les réponses, nous pouvons voir que certaines des réponses ne peuvent pas se produire. Par exemple, comme @ Linuxuser27 a signalé, chaque thread imprime 4 chiffres uniquement qui supprime les réponses aura plus de numéros imprimés. Un autre exemple de réponse inappropriée serait si l'une des réponses avait une valeur supérieure à 14 car le premier fil peut aller 0,2,4,6 et le 2ème pourrait le prendre à 8,10,12,14 mais pas plus élevé.

Étant donné que chacun des threads doit imprimer un numéro 4 fois et les chiffres imprimés par chaque thread doit être d'au moins 2+ le nombre précédent imprimé, certains des motifs ne peuvent pas être générés. Je ne donnerai pas ma réponse, mais n'est pas "tout ce qui précède" et ce n'est pas un, B et c.


3 commentaires

Chacun des chiffres doit être d'au moins 2+ le nombre précédent qu'ils ont imprimé Je pensais aussi, et j'étais tort :(


Si T2 avance plus que T1, T2's's's's's's's's's's actuel sera plus grand que celui du courant de T1, de sorte que lorsque T1 reprend le processeur de T2, X assumera le courant de T1 < / Code>, et que le courant inférieur sera imprimé après le plus haut. Donc, la sortie peut toujours descendre.


J'ai édité ma réponse. Ce que je voulais dire, c'est que le numéro de T1 monte toujours d'au moins 2 à partir de ce que T1 est également imprimé le numéro de T2.