OVH Cloud OVH Cloud

probleme Thread dans ecran Swing

7 réponses
Avatar
seb
Bonjour,

J'ai un probleme avec mon interface swing : un ecran doit lancer un thread
et se servir de ce thread pour mettre a jour une JProgressBar et le Panel
que contient l'ecran.
L'ecran "gele" alors qu'on ne voit nulle part dans les log une boucle
infinie.
Je precise que le gel est aleatoire, il ne se produit pas a chaque execution
du code mais de temps en temps, sans que j'ai pu trouver ce qui pouvait
generer ca.
Ci dessous le code qui appelle le thread :

public void appelEcranSuivant()

{

int nbreInj = _recupererNbreInj;

final JPanel parent = this;

_getBoutonSuivant().setEnabled(false);

_getBarreProgress().setVisible(true);

_getBarreProgress().setMaximum(nbreInj);

_getBarreProgress().setValue(0);

Runnable tache = new Runnable()

{

public void run()

{

int i = 0;

_resultats = new ArrayList();

// Appelle l'injection des types de site


_injecterTypesDeSite(getGestionnaireInjCatalogue().getInjectionCatalogues(),
i);

// Appelle l'injection des types d'identifiant


_injecterTypesIdentifiant(getGestionnaireInjCatalogue().getInjectionCatalogu
es(), i);

// Appelle l'injection des unites de calcul


_injecterUnitesDeCalcul(getGestionnaireInjCatalogue().getInjectionCatalogues
(), i);

// Appelle l'injection des libelles de facture


_injecterLibellesDeFacture(getGestionnaireInjCatalogue().getInjectionCatalog
ues(), i);

// Appelle l'injection des classes de site


_injecterClassesDeSite(getGestionnaireInjCatalogue().getInjectionCatalogues(
), i);

// Appelle l'injection des catalogues


_injecterCatalogues(getGestionnaireInjCatalogue().getInjectionCatalogues(),
i);

getGestionnaireInjCatalogue().setResultats(_resultats);

IhsInjecteurCatalogue5 ihs5 = new
IhsInjecteurCatalogue5(getDialogue(), parent);

getDialogue().setContentPane(ihs5);

}

};

Thread leThread = new Thread(tache);

leThread.start();

}



dans les differentes methodes _injecterXXX on trouve a la fin les 2 lignes
suivantes :

i++;

_getBarreProgress().setValue(i);



Merci d'avance pour toute aide.

7 réponses

Avatar
ownowl
swing n'est pas thread safe, il faut replacer toutes les actions issue
d'autres threads dans le thread de gestion des événements par un
EventQueue.invokeLater ou EventQueue.invokeAndWait (il y a les mêmes
méthodes dans SwingUtilities)

Olivier

"seb" a écrit dans le message news:
40cd711e$0$21433$
Bonjour,

J'ai un probleme avec mon interface swing : un ecran doit lancer un thread
et se servir de ce thread pour mettre a jour une JProgressBar et le Panel
que contient l'ecran.
L'ecran "gele" alors qu'on ne voit nulle part dans les log une boucle
infinie.
Je precise que le gel est aleatoire, il ne se produit pas a chaque
execution

du code mais de temps en temps, sans que j'ai pu trouver ce qui pouvait
generer ca.
Ci dessous le code qui appelle le thread :

public void appelEcranSuivant()

{

int nbreInj = _recupererNbreInj;

final JPanel parent = this;

_getBoutonSuivant().setEnabled(false);

_getBarreProgress().setVisible(true);

_getBarreProgress().setMaximum(nbreInj);

_getBarreProgress().setValue(0);

Runnable tache = new Runnable()

{

public void run()

{

int i = 0;

_resultats = new ArrayList();

// Appelle l'injection des types de site



_injecterTypesDeSite(getGestionnaireInjCatalogue().getInjectionCatalogues(),

i);

// Appelle l'injection des types d'identifiant



_injecterTypesIdentifiant(getGestionnaireInjCatalogue().getInjectionCatalogu

es(), i);

// Appelle l'injection des unites de calcul



_injecterUnitesDeCalcul(getGestionnaireInjCatalogue().getInjectionCatalogues

(), i);

// Appelle l'injection des libelles de facture



_injecterLibellesDeFacture(getGestionnaireInjCatalogue().getInjectionCatalog

ues(), i);

// Appelle l'injection des classes de site



_injecterClassesDeSite(getGestionnaireInjCatalogue().getInjectionCatalogues(

), i);

// Appelle l'injection des catalogues



_injecterCatalogues(getGestionnaireInjCatalogue().getInjectionCatalogues(),

i);

getGestionnaireInjCatalogue().setResultats(_resultats);

IhsInjecteurCatalogue5 ihs5 = new
IhsInjecteurCatalogue5(getDialogue(), parent);

getDialogue().setContentPane(ihs5);

}

};

Thread leThread = new Thread(tache);

leThread.start();

}



dans les differentes methodes _injecterXXX on trouve a la fin les 2 lignes
suivantes :

i++;

_getBarreProgress().setValue(i);



Merci d'avance pour toute aide.






Avatar
Bruno Jouhier
"seb" a écrit dans le message de
news:40cd711e$0$21433$
Bonjour,

J'ai un probleme avec mon interface swing : un ecran doit lancer un thread
et se servir de ce thread pour mettre a jour une JProgressBar et le Panel
que contient l'ecran.
L'ecran "gele" alors qu'on ne voit nulle part dans les log une boucle
infinie.


Souvent, quand un programme multi-thread "gêle", ce n'est pas dû à une
boucle infinie, mais plutôt à un deadlock (2 threads qui attendent
mutuellement que l'autre libère une ressource). Pour voir si le blocage est
dû à une boucle ou à un deadlock, il suffit en général de regarder
l'utilisation CPU. Si on a une boucle infinie, le CPU est utilisé à 100%, si
on a un deadlock, il est utilisé à 0% mais le processus est bloqué.

Bruno.

Je precise que le gel est aleatoire, il ne se produit pas a chaque
execution

du code mais de temps en temps, sans que j'ai pu trouver ce qui pouvait
generer ca.
Ci dessous le code qui appelle le thread :

public void appelEcranSuivant()

{

int nbreInj = _recupererNbreInj;

final JPanel parent = this;

_getBoutonSuivant().setEnabled(false);

_getBarreProgress().setVisible(true);

_getBarreProgress().setMaximum(nbreInj);

_getBarreProgress().setValue(0);

Runnable tache = new Runnable()

{

public void run()

{

int i = 0;

_resultats = new ArrayList();

// Appelle l'injection des types de site



_injecterTypesDeSite(getGestionnaireInjCatalogue().getInjectionCatalogues(),

i);

// Appelle l'injection des types d'identifiant



_injecterTypesIdentifiant(getGestionnaireInjCatalogue().getInjectionCatalogu

es(), i);

// Appelle l'injection des unites de calcul



_injecterUnitesDeCalcul(getGestionnaireInjCatalogue().getInjectionCatalogues

(), i);

// Appelle l'injection des libelles de facture



_injecterLibellesDeFacture(getGestionnaireInjCatalogue().getInjectionCatalog

ues(), i);

// Appelle l'injection des classes de site



_injecterClassesDeSite(getGestionnaireInjCatalogue().getInjectionCatalogues(

), i);

// Appelle l'injection des catalogues



_injecterCatalogues(getGestionnaireInjCatalogue().getInjectionCatalogues(),

i);

getGestionnaireInjCatalogue().setResultats(_resultats);

IhsInjecteurCatalogue5 ihs5 = new
IhsInjecteurCatalogue5(getDialogue(), parent);

getDialogue().setContentPane(ihs5);

}

};

Thread leThread = new Thread(tache);

leThread.start();

}



dans les differentes methodes _injecterXXX on trouve a la fin les 2 lignes
suivantes :

i++;

_getBarreProgress().setValue(i);



Merci d'avance pour toute aide.






Avatar
seb
"Bruno Jouhier" a écrit dans le message de
news:40cdafdd$0$313$
Souvent, quand un programme multi-thread "gêle", ce n'est pas dû à une
boucle infinie, mais plutôt à un deadlock (2 threads qui attendent
mutuellement que l'autre libère une ressource). Pour voir si le blocage
est

dû à une boucle ou à un deadlock, il suffit en général de regarder
l'utilisation CPU. Si on a une boucle infinie, le CPU est utilisé à 100%,
si

on a un deadlock, il est utilisé à 0% mais le processus est bloqué.

Bruno.


Merci pour ton aide, et merci egalement a Olivier.

Il n'y a pas d'utilisation du CPU donc on aurait un deadlock. Ceci dit les
differentes methodes appelees dans le thread font des mises a jour en base,
et apres avoir ferme l'ecran on constate que les donnees ont bien ete mises
a jour dans la base. De plus le probleme ne se reproduit pas a chaque fois
que je lance l'appli mais aleatoirement.
Si on avait affaire a un deadlock le probleme se produirait a chaque fois
non ?

Avatar
Bruno Jouhier
Si on avait affaire a un deadlock le probleme se produirait a chaque fois
non ?


Non, les deadlocks se produisent en général de manière aléatoire. Le
scénario typique est celui dans lequel un thread T1 essaie d'acquérir les
verrous L1 et L2 (dans cette ordre) et un autre thread T2 essaie d'acquérir
L2 et L1.

Si on tombe dans la séquence suivante:

T1 prend le verrou L1
T2 prend le verrou L2
T1 demande le verrou L2 et bloque en attendant que T2 le libère.
T2 demande le verrou L1 et bloque en attendant que T1 le libère.

il y a deadlock!

Si on a plus de chance, on peut avoir la séquence suivante:

T1 prend L1
T1 prend L2
T1 libère L2
T2 prend L2
T2 demande L1 et bloque
T1 libère L1
T2 obtient L1
T2 libère L1
T2 libère L2

Les 2 threads sont passés sans s'interbloquer (il y a d'autres séquences qui
passent, par ex toutes le opérations de L1 peuvent précéder toutes celles de
L2 ou l'inverse).

Bruno.

Avatar
Bruno Tignac
Salut,

Si t'es sous Linux, kill -3 <le pid de ta jvm bloquee>

tu recupere un javacore qui te donne les stacktraces des appels en attente.

Bruno

ownowl wrote:

swing n'est pas thread safe, il faut replacer toutes les actions issue
d'autres threads dans le thread de gestion des événements par un
EventQueue.invokeLater ou EventQueue.invokeAndWait (il y a les mêmes
méthodes dans SwingUtilities)

Olivier


Avatar
Xavier Tarrago
L'utilisation de swing est incorrecte. Si j'ai bien compris, tu lances un
thread (on l'appelle worker) qui exécute un Runnable (tache). La méthode
tache.run() qui s'exécute dans le worker thread appelle des méthodes
d'objets swing (_getBarreProgress().setValue()). C'est interdit. Les appels
à des objets swing ne sont pas synchronisés et ne doivent être faits que
depuis le thread swing.

La solution est de remplacer
_getBarreProgress().setValue(i);

par quelque chose comme
SwingUtilities.invokeLater( new Runnable () {
public void run() {
_getBarreProgress().setValue(i);
}
});

"seb" a écrit dans le message de
news:40cd711e$0$21433$
Bonjour,

J'ai un probleme avec mon interface swing : un ecran doit lancer un thread
et se servir de ce thread pour mettre a jour une JProgressBar et le Panel
que contient l'ecran.
L'ecran "gele" alors qu'on ne voit nulle part dans les log une boucle
infinie.
Je precise que le gel est aleatoire, il ne se produit pas a chaque
execution

du code mais de temps en temps, sans que j'ai pu trouver ce qui pouvait
generer ca.
Ci dessous le code qui appelle le thread :

public void appelEcranSuivant()

{

int nbreInj = _recupererNbreInj;

final JPanel parent = this;

_getBoutonSuivant().setEnabled(false);

_getBarreProgress().setVisible(true);

_getBarreProgress().setMaximum(nbreInj);

_getBarreProgress().setValue(0);

Runnable tache = new Runnable()

{

public void run()

{

int i = 0;

_resultats = new ArrayList();

// Appelle l'injection des types de site



_injecterTypesDeSite(getGestionnaireInjCatalogue().getInjectionCatalogues(),

i);

// Appelle l'injection des types d'identifiant



_injecterTypesIdentifiant(getGestionnaireInjCatalogue().getInjectionCatalogu

es(), i);

// Appelle l'injection des unites de calcul



_injecterUnitesDeCalcul(getGestionnaireInjCatalogue().getInjectionCatalogues

(), i);

// Appelle l'injection des libelles de facture



_injecterLibellesDeFacture(getGestionnaireInjCatalogue().getInjectionCatalog

ues(), i);

// Appelle l'injection des classes de site



_injecterClassesDeSite(getGestionnaireInjCatalogue().getInjectionCatalogues(

), i);

// Appelle l'injection des catalogues



_injecterCatalogues(getGestionnaireInjCatalogue().getInjectionCatalogues(),

i);

getGestionnaireInjCatalogue().setResultats(_resultats);

IhsInjecteurCatalogue5 ihs5 = new
IhsInjecteurCatalogue5(getDialogue(), parent);

getDialogue().setContentPane(ihs5);

}

};

Thread leThread = new Thread(tache);

leThread.start();

}



dans les differentes methodes _injecterXXX on trouve a la fin les 2 lignes
suivantes :

i++;

_getBarreProgress().setValue(i);



Merci d'avance pour toute aide.






Avatar
seb
Ca a regle le probleme effectivement.
Merci.

"Xavier Tarrago" a écrit dans le message
de news:camad3$hf2$
L'utilisation de swing est incorrecte. Si j'ai bien compris, tu lances un
thread (on l'appelle worker) qui exécute un Runnable (tache). La méthode
tache.run() qui s'exécute dans le worker thread appelle des méthodes
d'objets swing (_getBarreProgress().setValue()). C'est interdit. Les
appels

à des objets swing ne sont pas synchronisés et ne doivent être faits que
depuis le thread swing.

La solution est de remplacer
_getBarreProgress().setValue(i);

par quelque chose comme
SwingUtilities.invokeLater( new Runnable () {
public void run() {
_getBarreProgress().setValue(i);
}
});

"seb" a écrit dans le message de
news:40cd711e$0$21433$
Bonjour,

J'ai un probleme avec mon interface swing : un ecran doit lancer un
thread


et se servir de ce thread pour mettre a jour une JProgressBar et le
Panel


que contient l'ecran.
L'ecran "gele" alors qu'on ne voit nulle part dans les log une boucle
infinie.
Je precise que le gel est aleatoire, il ne se produit pas a chaque
execution

du code mais de temps en temps, sans que j'ai pu trouver ce qui pouvait
generer ca.
Ci dessous le code qui appelle le thread :

public void appelEcranSuivant()

{

int nbreInj = _recupererNbreInj;

final JPanel parent = this;

_getBoutonSuivant().setEnabled(false);

_getBarreProgress().setVisible(true);

_getBarreProgress().setMaximum(nbreInj);

_getBarreProgress().setValue(0);

Runnable tache = new Runnable()

{

public void run()

{

int i = 0;

_resultats = new ArrayList();

// Appelle l'injection des types de site





_injecterTypesDeSite(getGestionnaireInjCatalogue().getInjectionCatalogues(),

i);

// Appelle l'injection des types d'identifiant





_injecterTypesIdentifiant(getGestionnaireInjCatalogue().getInjectionCatalogu

es(), i);

// Appelle l'injection des unites de calcul





_injecterUnitesDeCalcul(getGestionnaireInjCatalogue().getInjectionCatalogues

(), i);

// Appelle l'injection des libelles de facture





_injecterLibellesDeFacture(getGestionnaireInjCatalogue().getInjectionCatalog

ues(), i);

// Appelle l'injection des classes de site





_injecterClassesDeSite(getGestionnaireInjCatalogue().getInjectionCatalogues(

), i);

// Appelle l'injection des catalogues





_injecterCatalogues(getGestionnaireInjCatalogue().getInjectionCatalogues(),

i);

getGestionnaireInjCatalogue().setResultats(_resultats);

IhsInjecteurCatalogue5 ihs5 = new
IhsInjecteurCatalogue5(getDialogue(), parent);

getDialogue().setContentPane(ihs5);

}

};

Thread leThread = new Thread(tache);

leThread.start();

}



dans les differentes methodes _injecterXXX on trouve a la fin les 2
lignes


suivantes :

i++;

_getBarreProgress().setValue(i);



Merci d'avance pour toute aide.