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

Langage Java Discussion :

Synchronisation et accès concurrents


Sujet :

Langage Java

  1. #1
    Membre averti

    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    464
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 464
    Points : 332
    Points
    332
    Par défaut Synchronisation et accès concurrents
    Bonjour,

    J'ai essayé plusieurs méthodes mais ça ne fonctionne pas comme je veux.
    Voici ce que je veux obtenir : je dispose d'un DesktopPane et des traitements consécutifs à faire. Chaque traitement se déroule dans sa propre fenêtre interne. Je voudrai que chaque nouvelle fenêtre soit bloquée tant que la précédente n'a pas fini son traitement. Comment faire ? J'ai lu les trois articles sur les Thread et la synchronisation.
    Voici un bout de code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    	protected void verifierTout() 
    	{
    		bureau.vider();
        	        for(Table table : Table.values())
        	        {
        		      verifier(table, true);
        	        }
    	}
    Donc pour chaque table, la méthode verifier ouvre une fenêtre et traite la table. Pour le moment toutes les fenêtres apparaissent en même temps sur le bureau et les traitements se font dans un ordre aléatoire avec des problèmes d'accès concurrents. A priori aucune action n'écrit dans la base.
    C'est en respectant les autres que l'on se fait respecter.

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    ton extrait de code ne présente aucun thread ni synchronized, donc difficile de te dire ou est le problème. Mets nous cette partie de code.

    Sur le principe, on synchronise sur les instances communes qui sont manipulées par chaque thread, et qui ne peuvent pas être manipulée par plusieurs threads en même temps sans que les données soient corrompues, ou dont l'implémentation n'est pas prévue pour l'être. Le synchronized empeche un thread d'éxécuter le block (ou la méthode) synchronisée si un autre thread est déjà entrain de le faire, mais ne garanti pas l'ordre d'éxécution : si plusieurs thread sont en attente sur le synchronized, et que le verrou est libéré, n'importe lequel de ces threads en attente va obtenir le verrou et exécuter le code.

    Si tu veux pourvoir lancer des traitements consécutifs, tu peux utiliser le même thread qui exécute chacun des traitements, l'un après l'autre, et tu n'auras pas d'accès concurrents. Regarde également du coté de java.util.concurrent.ExecutorService.

    Si le but est de lancer 3 threads simultanés, mais que certains d'entre doivent à un moment attendre qu'un autre ait fini son traitement avant de continuer le sien, il y'a également la classe CountDownLatch qui peut t'aider.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre averti

    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    464
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 464
    Points : 332
    Points
    332
    Par défaut
    Tout d'abord merci de ta réponse. je vais essayer de préciser les choses.
    Dans ma classe principale un clic sur un menu déclenche l'action verifierTout()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    	protected void verifierTout() 
    	{
    		bureau.vider();
        	       for(Table table : Table.values())
        	       {
        		       verifier(table, true);
         	       }
    	}
    La méthode vider permet dde supprimer toutes les fenêtres internes du DesktopPane.
    La méthode vérifier est définie ci-dessous
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    	protected synchronized void verifier(Table table, boolean toutVerifier) 
    	{
    		this.bureau.ajoute(new DossierVerificateur(table, toutVerifier));
    	}
    J'ai mis synchronized ici mais je ne suis pas sûr que ce soit utile ou efficace.

    La classe DossierVerificateur est
    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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
     
    public class DossierVerificateur extends DossierTexte 
    {
    	private Verif v;
    	private Table table;
     
    	public DossierVerificateur(Table t, boolean toutVerifier) 
    	{
    		super("Vérification de la table : " + t);
    		MenuSelectionManager.defaultManager().clearSelectedPath();  
    		table = t;
    		switch (t)
    		{
    			case CENTRES_CIVILISATIONS : 
    				v = new VerifCentresCiv(this);
    				break;
    			case CIVILISATIONS : 
    				v = new VerifCiv(this);
    				break;
    			case DESSINS_FLEUVES : 
    				v = new VerifDessinsFl(this);
    				break;
    			case DESSIN_NOMS : 
    				v = new VerifDessinsNoms(this);
    				break;
    			case FLEUVES : 
    				v = new VerifFleuves(this);
    				break;
    			case INFOS_TERRITOIRES : 
    				v = new VerifInfos(this);
    				break;
    			case LIMES : 
    				v = new VerifLimes(this); 
    				break;
    		    case MERS : 
    		    	v = null;
    		    	this.setTexte("Rien à vérifier pour la table MERS");
    		    	break;
    		    case NOMS_TERRITOIRES : 
    		    	v = new VerifNomsTer(this);
    		    	break;
    		    case PARAGRAPHES : 
    		    	v = new VerifPar(this);
    		    	break;
    		    case POINTS : 
    		    	v = new VerifPoints(this);
    		    	break;
    		    case POINTS_NOMS_FLEUVES : 
    		    	v = null;
    		    	this.setTexte("Rien à vérifier pour la table POINTS_NOMS_FLEUVES");
    		    	break;
    		    case POURTOURS : 
    		    	v = new VerifPourtours(this);
    		    	break;
    		    case POURTOURS_LIMES : 
    		    	v = new VerifPourtoursLimes(this);
    		    	break;
    		    case SUIVANTS_PARAGRAPHES : 
    		    	v = null;
    		    	this.setTexte("Rien à vérifier pour la table SUIVANTS_PARAGRAPHES");
    		    	break;
    		    case TERRES : 
    		    	v = null;
    		    	this.setTexte("Rien à vérifier pour la table TERRES");
    		    	break;
    		    case TERRITOIRES : 
    		    	v = null;
    		    	this.setTexte("Rien à vérifier pour la table TERRITOIRES");
    		    	break;
    		    default : throw new IllegalArgumentException(t + " n'est pas une table valide");
    		}
    		if (v != null) v.execute();
    		}
    	public Table getTable() 
    	{
    		return table;
    	}
    }
    La classe DossierTexte est une InternalFrame avec un JTextArea

    La classe Verif est une extension d'un SwingWorker et utilise un ProgressMonitor
    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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
     
    public abstract class Verif extends SwingWorker<String,String> implements PropertyChangeListener 
    {
    	protected ProgressMonitor pm;
    	private DossierVerificateur dossier;
    	public Verif(DossierVerificateur d)
    	{
    		this.dossier = d;
    		String str = "Vérification de la table " + d.getTable() + "\n";
    		d.setTexte(str);
    		pm = new ProgressMonitor(d,str,"", 0,100);
    		pm.setMillisToDecideToPopup(200);
    		pm.setMillisToPopup(500);
    		this.addPropertyChangeListener(this);
    	}
     
    	public void process(List<String> list)
    	{
            for(String str : list) this.dossier.append(str);	
    	}
     
    	public synchronized void done()
        {
    		try 
    		{
    			String texte = get();
    			if (! texte.equals("")) this.dossier.setTexte(texte);
    		} 
    		catch (ConcurrentModificationException e)
    		{
    			System.out.println("accès concurrent");
    			e.printStackTrace();
    		}
    		catch (InterruptedException e) 
    		{
    			System.out.println("interruption");
    			e.printStackTrace();
    		} catch (ExecutionException e) 
    		{
    			System.out.println("execution");
    			e.printStackTrace();
    		}
        }
     
    	@Override
    	public void propertyChange(PropertyChangeEvent evt) 
    	{
            if ("progress" == evt.getPropertyName()) 
            {
                int progress = (Integer) evt.getNewValue();
                pm.setProgress(progress);
            }
    	}
    }
    Chaque classe VerifXXX sont des extensions de Verif, voici l'un de ces classes
    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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    public class VerifCiv extends Verif 
    {
     
    	public VerifCiv(DossierVerificateur d) 
    	{
    		super(d);
    	}
     
    	@Override
    	protected String doInBackground() throws Exception 
    	{
    		List<CivilisationGHM> orphelins = new ArrayList<CivilisationGHM>();
    		List<CivilisationGHM> liste = ConnexionBase.getListeCivilisations();
    		String problemes = "";
    		String message;
    		int total = liste.size();
    		setProgress(0);
    		for(int i = 0 ; i < total ; i++)
    		{
    			message = "traitement : " + (i+1) + " sur " + total + " OK !\n";
    			CivilisationGHM civ = liste.get(i);
    			if (! civ.isUtilise())
    			{
    				message = "civilisation " + civ.getNom() + "(" + civ.getIdentifiant() + ") " +
    						  "est orpheline !\n" ; 
    				problemes += message;
    			}
     
    			//si le centre courant a même civilisation que le prec
    			setProgress((int) 100*(i+1)/total);
    			publish(message);
    		}
    		return problemes;
    	}
    }
    Les diverses listes utilisées sont des listes de type de données et le détail n'est pas utile ici.

    En général j'ai une erreur d'accès concurrent sur la méthode done() de Verif sur la ligne : String texte = get();.
    Je voudrai donc que le traitement de CENTRES_CIVILISATIONS soit terminé avant de commencer celui dde CIVILISATIONS. A priori tout se fait dans le Thread principal et l'EDT. Ici le problème est le contraire du problème habituel : d'habitude on est gêné parce que l'interface graphique est figée pendant un traitement long, ici l'interface graphique s'affiche alors que le traitement est toujours en cours.
    C'est en respectant les autres que l'on se fait respecter.

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

Discussions similaires

  1. accés concurrent à une table
    Par shout dans le forum Oracle
    Réponses: 5
    Dernier message: 06/10/2005, 10h54
  2. Réponses: 22
    Dernier message: 25/08/2005, 16h03
  3. Lenteur et acces concurrent
    Par JeanMarc_T2k dans le forum Bases de données
    Réponses: 7
    Dernier message: 04/12/2004, 20h57
  4. acces concurrent avec delphi 5 entreprise
    Par Jean_paul dans le forum Bases de données
    Réponses: 2
    Dernier message: 30/11/2004, 20h19
  5. [EJB] Accès concurrents à la base de données
    Par cameleon2002 dans le forum Java EE
    Réponses: 10
    Dernier message: 23/09/2003, 11h31

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