Bonjour,
Il s'agit d'un problème faisant suite à 1 discussion précédente, que je délocalise, pour ne pas polluer le sujet initial de l'auteur (voir Actions concurrentes dans l'EDT)

Le sujet est assez simple, et la solution doit l'être tout autant...
mais pour l'instant, je ne l'ai pas trouvée.

Il s'agit d'exécuter une action longue dans Swing, sans bloquer l'EDT, et en donnant la possibilité à l'utilisateur :
  • de démarrer la tâche longue
  • de la mettre en pause ou de la reprendre
  • de la stopper définitivement


J'ai une classe permettant de gérer ce type de tâche, mal, puisque la méthode sensée mettre la tâche en pause bloque l'EDT (méthode sleep en rouge)
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
public abstract class MyTask implements Runnable {
	private int delai = 1000;
	private volatile Thread currentThread = null;

	public void run() {
		currentThread = Thread.currentThread();
		while (!currentThread.isInterrupted() && continueCondition()) {
			doMyTask();
			try {
				Thread.sleep(delai);
			} catch (InterruptedException exception) {
				onCancelled();
				break;
			}
		}
	}

	public void cancel() {
		currentThread.interrupt();
	}
	//Pose problème : méthode bloquant l'EDT
	public void sleep() {
		synchronized (this) {
			try {
				while (!currentThread.isInterrupted()) {
					this.wait();
				}
			} catch (InterruptedException e) {
				onCancelled();
			}
		}
	}

	public void wakeUp() {
		synchronized (this) {
			this.notify();
		}
	}

	public abstract void doMyTask();

	public abstract boolean continueCondition();

	public abstract void onCancelled();

}
  • doMyTask permet d'implémenter 1 tâche atomique (1 parcours de boucle...)
  • continueCondition est ta condition de continuité (de la boucle par exemple)
  • onCancelled, la méthode à implémenter en cas d'annulation



Ci dessous une classe de test implémentant MyTask (avec une tâche bidon consistant à boucler...):
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
 
public class TestThreads extends JFrame implements ActionListener {
	private static final long serialVersionUID = 1L;
	private JPanel mainPanel;
	private JButton btStart;
	private JButton btStop;
	private JButton btSleep;
	private JButton btWakeUp;
	private MyTask mytask;
	private Thread currentThread;
	private JLabel lblCompteur;
	private int compteur = 0;
 
	public static void main(String[] args) {
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			private TestThreads t;
 
			@Override
			public void run() {
				t = new TestThreads();
 
			}
		});
 
	}
 
	public TestThreads() {
		super();
		// Tâche
		mytask = new MyTask() {
 
			@Override
			public void onCancelled() {
				compteur = 0;
				updateLblCompteur();
			}
 
			@Override
			public void doMyTask() {
				compteur++;
				updateLblCompteur();
			};
 
			@Override
			public boolean continueCondition() {
				return compteur < 10000;
			}
		};
 
		// Fenêtre
		JFrame fen = new JFrame("Test threads");
		fen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		fen.setLayout(new BorderLayout());
		mainPanel = new JPanel(new FlowLayout());
		lblCompteur = new JLabel("0");
		mainPanel.add(lblCompteur);
		btStart = getButton("Start");
		btStop = getButton("Stop");
		btSleep = getButton("Sleep");
		btWakeUp = getButton("Reveil");
		fen.add(mainPanel, BorderLayout.NORTH);
		fen.pack();
		fen.setVisible(true);
	}
 
	/**
         * Création d'un bouton
         * 
         * @param text
         * @return
         */
	private JButton getButton(String text) {
		JButton bt = new JButton(text);
		bt.addActionListener(this);
		mainPanel.add(bt);
		return bt;
	}
 
	private void updateLblCompteur() {
		SwingUtilities.invokeLater(new Runnable() {
 
			@Override
			public void run() {
				lblCompteur.setText(compteur + "");
			}
		});
	}
 
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource().equals(btStart)) {
			currentThread = new Thread(mytask);
			currentThread.start();
		}
		if (e.getSource().equals(btStop))
			mytask.cancel();
		if (e.getSource().equals(btSleep)) {
			// Problème !!!!!!!!! Méthode bloquante
			mytask.sleep();
			System.out.println("pas sleep");
		}
		if (e.getSource().equals(btWakeUp))
			mytask.wakeUp();
	}
}
Logiquement, le thread de la tâche n'est pas lancé dans l'EDT :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
 
currentThread = new Thread(mytask);
currentThread.start();
donc pourquoi le wait sur mytask bloque t-il l'EDT ?