IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Concurrence et multi-thread Java Discussion :

Synch Thread interne avec FOStream


Sujet :

Concurrence et multi-thread Java

  1. #1
    Membre chevronné Avatar de broumbroum
    Profil pro
    Inscrit en
    Août 2006
    Messages
    406
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Suisse

    Informations forums :
    Inscription : Août 2006
    Messages : 406
    Par défaut Synch Thread interne avec FOStream
    Bonjour!

    Je suis en train de me perdre dans la synchronisation du méthode appartenant à un gestionnaire de cache (type HIFO pour un peu frimer): quel objet mettre au verrou synchronized??? Le tutoriel de ®om ne m'aide pas plus que ça.... J'ai un chargement trop long pour les objets pas trop gros comme 4ko env. ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
        private boolean swap(int pKey, Object pValue) {
            final int key = pKey;
            final Object value = pValue;
            cacheDisk.put(key, new File(cacheDisk_dir + File.separator + "_cache"+hashCode()+key+'.'+cacheDisk_ext));
            Thread t = new Thread(new Runnable() { public void run() {
                try {
                    new ObjectOutputStream(new FileOutputStream((File)cacheDisk.get(key))).writeObject(value);
                } catch(IOException e) { e.printStackTrace(); Thread.currentThread().interrupt(); }
            }}, "T-cache-swap");
            t.start();
            synchronized (pValue) { // ça fait pas de différence avec "this"! ???
                try {
                    t.join();
                    System.out.println(pKey + " swapped");
                } catch(InterruptedException e) { return false; } finally { return true; }
            }
        }

  2. #2
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Ta synchronisation ici ne sert à rien...

    Si tu veux attendre, le t.join() suffit.

    Quel est le problème?

    EDIT: De plus, lancer un thread, et faire un .join() juste après l'avoir lancé, ça revient au même que de ne pas lancer de nouveau thread et de faire le traitement dans ta méthode directement.

  3. #3
    Membre chevronné Avatar de broumbroum
    Profil pro
    Inscrit en
    Août 2006
    Messages
    406
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Suisse

    Informations forums :
    Inscription : Août 2006
    Messages : 406
    Par défaut
    c'est-à-dire que j'aimerais occuper un minimum de temps l'instance de cache.
    Car j'obtiens un overflow du "heap space java" après 1 ou 2 minutes d'écoulement...
    Note: je viens de placer des PhantomReference sur les flux d'entrée et de sortie du cache.

  4. #4
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Il faut surtout que tu ne sérialises pas tout le fichier comme ça, mais que tu l'écrives petit à petit (par blocs de 2Ko par ex)...

    ça n'a rien à voir avec des threads ou de la synchronisation.

  5. #5
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    Citation Envoyé par ®om
    De plus, lancer un thread, et faire un .join() juste après l'avoir lancé, ça revient au même que de ne pas lancer de nouveau thread et de faire le traitement dans ta méthode directement.
    +100 !!!!

    Citation Envoyé par broumbroum
    Car j'obtiens un overflow du "heap space java" après 1 ou 2 minutes d'écoulement...
    C'est un autre problème : tu utilises toutes la mémoire !

    Sinon quelques autres remarques :
    • Déjà ce serait bien de fermer tes flux (dans des bloc finally de préférence).
    • Il ne doit pas y avoir d'instruction return dans un bloc finally, car cela te masquerait n'importe quel autre return. Le compilateur devrait te signaler un warning pour cela.
    • Je ne vois pas du tout à quoi sert le synchronized, puisque le verrou que tu utilises n'est jamais utilisé ailleurs.




    Il faudrait également qu'on sache le but exact de cette méthode...


    a++

  6. #6
    Membre chevronné Avatar de broumbroum
    Profil pro
    Inscrit en
    Août 2006
    Messages
    406
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Suisse

    Informations forums :
    Inscription : Août 2006
    Messages : 406
    Par défaut performances du cache
    merci pour vos remarques!
    J'ai donc en effet remarqué l'inutilité du verrou à cet endroit, bien que je pense que ça ne fait aucun effet sur la vitesse de l'enlever. Par contre je constate évidemment que la mémoire est saturée avec les flux d'octets. La boucle passe plus de 1000x sur le swap en 2 minutes. J'ai donc un concept: Libérer la mémoire assignée durant les opérations de swap le plus rapidement possible. - Les PhantomReference ajoute un gain non négligeable pour une grande quantité d'opérations.
    - Adiguba me rappelle de fermer les les flux aussi, j'avais oublié...
    - pour ce qui de "synchronized", je n'active ce verrou que dans les méthodes appelant une mise en attente des threads: "Thread.wait()", "Thread.join()".
    - J'ai l'intention de réellement affecter à PhantomRef. toutes les références déclarées dans l'instance de cache, y compris les références locales. Par exemple, lorsque je fais un swap, l'objet à sérialiser dans le flux est immédiatement référencé sur le mode fantôme pour libérer l'adresse mémoire en RAM dès la fin du processus de swap.
    - la raison pour laquelle je m'attache à placer un processus "Thread" est le debuggage du cache, car la JVM n'afficherait pas la source de l'erreur d'overflow assez précisément. Habituellement, cela m'indiquerait un "AWT-EventQueue-1"; avec le nommage du processus "T-Cache-Swap" je ne me perds plus sur les origines des erreurs de la JVM.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
        private boolean swap(int pKey, Object pValue) {
            final int key = pKey;
            final Object value = pValue;
            cacheDisk.put(key, new File(cacheDisk_dir + File.separator + "_cache"+hashCode()+key+'.'+cacheDisk_ext));
            Thread t = new Thread(new Runnable() { public void run() {
                try {
                    oos = new ObjectOutputStream(fos = new FileOutputStream((File)cacheDisk.get(key)));
                    PhantomReference ph0 = new PhantomReference(fos, cacheBack);
                    PhantomReference ph1 = new PhantomReference(oos, cacheBack);
                    PhantomReference ph2 = new PhantomReference(value, cacheBack);
                    oos.writeObject(value);
                    oos = null;
                    fos = null;
                } catch(IOException e) { e.printStackTrace(); Thread.currentThread().interrupt(); }
            }}, "T-cache-swap");
            t.start();
            synchronized (pValue) {
                try {
                    t.join();
                    System.out.println(pKey + " swapped");
                } catch(InterruptedException e) { return false; } finally { return true; }
            }
        }

  7. #7
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par broumbroum
    Par contre je constate évidemment que la mémoire est saturée avec les flux d'octets. La boucle passe plus de 1000x sur le swap en 2 minutes.
    Donc en 2 minutes tu arraives à ouvrir plus de 1000 flux sans les refermer ! Et tu t'étonnes d'avoir des problèmes de mémoire ???
    Sans compter qu'en plus cela signifie que tu crées 1000 threads...

    Citation Envoyé par broumbroum
    J'ai donc un concept: Libérer la mémoire assignée durant les opérations de swap le plus rapidement possible.
    En général le GC optimise cela bien mieux que la plupart des developpeurs... donc le plus simple est de le laisser faire et de ne pas laisser trainer de référence...

    Citation Envoyé par broumbroum
    - Les PhantomReference ajoute un gain non négligeable pour une grande quantité d'opérations.
    Les PhantomReference permettent simplement de connaitre le moment où la référence sera supprimé par le GC (lire Comprendre les Références en Java). Mais en aucun cas elles ne permettent de libérer la mémoire plus rapidement...

    Citation Envoyé par broumbroum
    - Adiguba me rappelle de fermer les les flux aussi, j'avais oublié...
    Alors pourquoi tu ne les fermes toujours pas ??? D'ailleurs tu n'a tenu compte d'aucune de mes remarques


    Citation Envoyé par broumbroum
    - pour ce qui de "synchronized", je n'active ce verrou que dans les méthodes appelant une mise en attente des threads: "Thread.wait()", "Thread.join()".
    Mais synchronized n'est utile que dans le cas où deux threads différents utilise le même verrou (la reference passé à au mot clef synchronized()). Est-ce que tu effectues un synchronized(pValue) autre part dans ton code ? Sinon c'est complètement inutile...


    Citation Envoyé par broumbroum
    - J'ai l'intention de réellement affecter à PhantomRef. toutes les références déclarées dans l'instance de cache, y compris les références locales. Par exemple, lorsque je fais un swap, l'objet à sérialiser dans le flux est immédiatement référencé sur le mode fantôme pour libérer l'adresse mémoire en RAM dès la fin du processus de swap.
    Comme je l'ai dit plus haut, PhantomReference ne sert pas à accélérer la libération des objets...

    Citation Envoyé par broumbroum
    - la raison pour laquelle je m'attache à placer un processus "Thread" est le debuggage du cache, car la JVM n'afficherait pas la source de l'erreur d'overflow assez précisément. Habituellement, cela m'indiquerait un "AWT-EventQueue-1"; avec le nommage du processus "T-Cache-Swap" je ne me perds plus sur les origines des erreurs de la JVM.
    "AWT-EventQueue-1" signifie que le thread est celui de l'EDT (thread de gestion de l'interface graphique).
    Mais dans les deux cas tu devrais avoir un stacktrace indiquant précisément l'origine de l'erreur...

    Faire un thread uniquement pour avoir des stacktrace "plus joli" est un peu bête... surtout si on se trouve dans une méthode qui sera appelé un grand nombre de fois...


    Bref ta méhode swap devrait plutôt ressembler à ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    	private boolean swap(final int key, final Object value) {
     
    		cacheDisk.put(key, new File(cacheDisk_dir + File.separator + "_cache" + hashCode() + key + '.' + cacheDisk_ext));
    		try {
    			FileOutputStream fos = new FileOutputStream((File) cacheDisk
    					.get(key));
    			try {
    				ObjectOutputStream oos = new ObjectOutputStream(fos);
    				try {
    					oos.writeObject(value);
    				} finally {
    					oos.close();
    				}
    			} finally {
    				fos.close(); // fermeture du flux
    			}
    		} catch (IOException e) {
    			e.printStackTrace();
    			return false;
    		}
    		return true;
    	}

    Mais je ne sais toujours pas quel est le but de cette méthode... Cela ne te crée pas trop de fichier ???


    a++

  8. #8
    Membre chevronné Avatar de broumbroum
    Profil pro
    Inscrit en
    Août 2006
    Messages
    406
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Suisse

    Informations forums :
    Inscription : Août 2006
    Messages : 406
    Par défaut Cache et Buffer
    Merci pour tout ton commentaire! Je disais donc que la mémoire est saturée après 1000+ passages au swap. Il y a un timer qui charge le cache très fréquemment, quasiment à chaque requête du programme vers les resources.
    Au sujet des PhantomReference, et autres Reference, tout est dit. J'ai envie d'ajouter que le fait de connaître le moment de la libération de l'adresse mémoire d'une instance Java est cruciale dans des applications conséquentes en termes de resources objet. ça fait un peu penser aux adresses mémoire de C+ qui sont en générales plus fastidieuses à digérer par le code. Sans utiliser de Reference pour le cache et le buffer des resources, le programme ne suit pas le temps de chargement et l'occupation mémoire en temps réel. Qui pourrait en dire plus de cette affirmation?

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Programme international avec IHM multi-langues
    Par calogerogigante dans le forum API standards et tierces
    Réponses: 6
    Dernier message: 26/04/2006, 00h49
  2. Thread Synchronisation avec structure FIFO ??
    Par vincedom dans le forum MFC
    Réponses: 5
    Dernier message: 30/03/2006, 06h00
  3. Thread--> problème avec ThreadProc
    Par stof dans le forum MFC
    Réponses: 33
    Dernier message: 08/06/2005, 13h47
  4. [Thread] Probleme avec mon Timer
    Par Nico66 dans le forum EDT/SwingWorker
    Réponses: 10
    Dernier message: 02/06/2005, 17h10
  5. Thread probs avec WaitFor()
    Par pixelrock dans le forum C++Builder
    Réponses: 2
    Dernier message: 04/11/2002, 09h40

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo