Concurrence en Java

Constructeur de copie des listes

L'auteur de ce sujet a trouvé une solution à son problème.
Staff
Auteur du sujet

Bonjour,

Je m'exerce à utiliser la librairie Jade en Java. Et j'ai rencontré un problème que j'ai résolu mais dont je ne comprend pas la provenance.

Jade est une librairie multi-agent qui permet de gérer un environnement avec des nombreux agents (ici on peut considérer que agent = thread). Dans mon cas, je veux créer $N$ agents. Chaque agent est d'abord crée puis initialisé.

Pour cela la méthode qui créer les agents demande de lui passer un Object[]. Cet argument pourra ensuite être récupéré par l'agent grâce à la méthode getArguments().

Chaque agent, une fois crée est est lancé et est initialisé par la méthode setup().

Mon problème est le suivant. J'ai la liste de tous le noms des agents, et je veux la passer aux agents en supprimant son propre nom de la liste. Cela peut se faire de deux façons :

  • Soit avant la création de l'agent en créant une nouvelle liste qui lui sera passée en argument
  • Soit dans la méthode setup en récupérant la liste de tous les noms des agents puis en supprimant son propre nom

La première méthode fonctionne sans problème. La deuxième pas du tout.

Comme Jade (et Java) sont assez verbeux, je ne vous passe qu'un extrait du code (avec la deuxième solution).

Ici le code qui permet la création de l'agent. On remarque donc que l'on passe à chaque fois a objtab la liste contenant tous les noms des agents.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
for(int i = 0 ; i< nAgents ; i ++) {
            agentListName.add(i, "Agent Explorer "+String.valueOf(i));
        }
        for(int i = 0 ; i<nAgents ; i++) {
            c = containerList.get("container");
            try {
                agentName=agentListName.get(i);
                Object[] objtab=new Object[]{agentListName};
                AgentController ag=c.createNewAgent(agentName,AgentExplorer.class.getName(),objtab);
                agentList.add(ag);
                System.out.println(agentName+" launched");
            } catch (StaleProxyException e) {
                e.printStackTrace();
            }
        }

Ici le code appelé pour l’initialisation de l'agent :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
protected void setup() {
        super.setup();

        //get the parameters given into the object[]
        final Object[] args = getArguments();
        if(args!=null){
            data = (List<String>)args[0];
        }
        else{
            System.out.println("Erreur lors du tranfert des parametres");
        }
                data.remove(this.getLocalName()); //On supprime le nom de l'agent dans la liste
        for(String o : data) {
            System.out.println("Agent :"+this.getLocalName()+"; Arg : "+o.toString());
        }

    }

En faisant de cette manière, j'obtiens une erreur à la compilation si il ya plusieurs agents. Cela vient du fait que l'objet data est partagé entre chaque agent. C'est comme si c'était une liste synchronisée. Chaque agent à accès à la même liste. Ce qui me parait étrange puisque clairement ce n'est pas le comportement souhaité. De toute façon la première méthode fonctionne, donc les listes sont bien censés pointées à des endroits différents en mémoire.

Donc ma question c'est comment se fait-il que le pointeur de data soit dans ce cas partagé par tous les agents au lieu d'être copié ? Le code étant un poil long vous pourrez le trouver sur le pastebin suivant (il vous faudra télécharger Jade et inclure les jar dans le projet) :

AgentExplorer.java Environement.java

Deux petites questions bonus :

  • Je passe en argument un Object[] et pourtant ma liste se trouve dans Object[0] pourquoi ? Eclipse de toute façon m'indique une erreur de cast.
  • Est-ce qu'il n'existe pas une manière plus Javanesque pour les boucles for quand elles parcourent des entiers ?

Cordialement,

Saroupille

+0 -0

J'ai lu en diagonale, mais, à priori, le comportement est logique. Comme tu le dis toi même, tu ne donne pas à chaque agent une liste des agent, mais une référence de la liste des agents. La liste reste unique. Il faudrait copier la liste pour chaque agent, pour que chaque agent ait sa propre copie, éditable à volonté.

+0 -0
Staff
Auteur du sujet

Mais cette ligne Object[] objtab=new Object[]{agentListName}; ne s'occupe pas de faire la copie ? Et si elle ne le fait pas, alors pourquoi la méthode 1 que j'implémente ainsi :

1
2
3
List<String> tmp = new ArrayList<String>(agentListName);
                tmp.remove(agentName);
                Object[] objtab=new Object[]{tmp};

Semble fonctionner ?

Le constructeur d'ArrayList fait une copie en profondeur mais pas le constructeur Object[] ?

C'est piégeur tout de même…

Édité par Saroupille

+0 -0

Cette réponse a aidé l'auteur du sujet

J'ai quelques doutes sur la syntaxe Java,

new Object[]{agentListName}; c'est un tableau d'objets initialisé avec un objet qui est agentListname

new Object[](agentListName); serait plus correct, mais il me semble que le tableau n'est pas un type objet en Java, et donc n'a pas de constructeur.

Le fait de faire new ArrayList<String>(agentListName); passe par le constructeur de ArrayList, qui fait une recopie. Object[]{} ne fait que de l'assignation.

Ca répond d'ailleurs à

  • Je passe en argument un Object[] et pourtant ma liste se trouve dans Object[0] pourquoi ? Eclipse de toute façon m'indique une erreur de cast.

L'argument est un Object[] de taille 1 dont l'élément 0 est (la référence de) agentListName dans un cas, et de tmp, un ArrayList construit par recopie de agentListName, dans l'autre.

+2 -0

En fait, l'erreur vient d'une confusion de comportement C++ vs Java.

Pour les programmeurs C++, vous devriez considérer qu'en Java, tout ce qui n'est pas primitif est nécessairement un pointeur.

Si on tente de transcoder le code Java :

1
2
3
List<String> monARrayList = new ArrayList<String>();
...
new Object[]{ monArrayList }

Ca donnerait quelque chose approchant :

1
2
3
4
vector<string>* monArrayList = new vector<string>();
...
vector<string>** temporaire = new (vector<string>*)[1];
temporaire[0] = monArrayList;

Et donc l'erreur doit apparaître claire maintenant: il n'y a pas de copie de la liste de départ.

Ma plateforme avec 23 jeux de société classiques en 6 langues et 13000 joueurs: http://qcsalon.net/ | Apprenez à faire des sites web accessibles http://www.openweb.eu.org/

+0 -0

Franchement je ne comprends pas l’attitude niveau gamin de donner "-1". C'était pareil sous le SdZ, regardez moi tout ces pseudos d'anciens SdZ, vous vous étonnez après de vous retrouver à 15 dans un forum ? Il faut savoir évoluer bon sang, si vous continuez à rejeter la moindre pensée d'une personne vous continuerez à vous retrouver à 15. Moi perso ça me fait plaisir de voir toutes ces personnes qui faisaient essentiellement du C ou C++ s'ouvrir vers d'autres technos, d'où ma remarque à Natalya d'ailleurs, mais visiblement l'humour est toujours aussi absent.

Miagiste. A la recherche d'un emploi sur Paris (QlikView ou Java). En savoir plus sur moi : https://gokan-ekinci.appspot.com

+0 -0

Bref, pour reprendre l'exemple de QuentinC,

J'aurais peut-être utilisé cette syntaxe :

1
2
3
List<String> monArrayList = new ArrayList<String>();

new Object[]{ monArrayList };
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <iostream>
#include <vector>
using namespace std;

int main() {
    std::vector<string*>* list = new std::vector<string*>();

    auto temp = new std::vector<vector<string*>*>();
    temp->push_back(list);
    return 0;
}

String est une classe, son instance passe lui aussi par copie de référence.

Miagiste. A la recherche d'un emploi sur Paris (QlikView ou Java). En savoir plus sur moi : https://gokan-ekinci.appspot.com

+0 -0

Moi perso ça me fait plaisir de voir toutes ces personnes qui faisaient essentiellement du C ou C++ s'ouvrir vers d'autres technos, d'où ma remarque à Natalya d'ailleurs, mais visiblement l'humour est toujours aussi absent.

Gugelhupf

J'ai jamais vraiment été fermé sur les autres technos, c'est juste que, dans la plupart des cas, soit quelqu'un a répondu avant, soit je ne suis pas capable de répondre. Ici, c'était une simple question de typage est d'instanciation. C'est universel, il n'était pas utile d'être un pro du Java pour répondre, et je suis passé au bon moment.

+0 -0

(Je préférerais que cette discussion n'ait pas lieu ici ; si un modérateur a les moyens et le temps de séparer ça dans un nouveau fil…)

Franchement je ne comprends pas l’attitude niveau gamin de donner "-1".

Les -1 et +1 servent à identifier la pertinence des messages. Ils ne sont pas supposés traduire autre chose que "ce message (ne) contribue (pas) à la conversation". Dans un forum technique, les discussions sont censées rester techniques - les blagues, les clins d'œil, etc. ne sont pas nécessairement modérés, mais il ne faut pas s'étonner que les gens les jugent comme ce qu'ils sont : du bruit, pas de la techniques.

L'attitude de gamin, c'est plutôt de ne pas assumer et de venir se plaindre après, tu ne penses pas ? Personne ne te "moinsse" pour te rejeter ou pour te faire comprendre que tu n'es pas à ta place. Ton message ne contribue pas à la discussion, il se fait moinsser, c'est vraiment normal et ça n'a absolument rien de personnel.

(Je précise à toute fin utile que je ne t'ai pas mis -1, précisément parce que je sais que c'est généralement mal interprété ; par ailleurs, crois-moi sur parole, je passe mon temps à faire des remarques incongrues et à me faire moinsser moi aussi. Tu vois, tu n'es pas le seul.)

+2 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte