Les threads se terminent de différentes manières selon qu'ils soient démons ou utilisateurs.
La méthode Runtime.exit() arrête tous les threads en cours d'exécution.
Un thread démon continue indéfiniment si aucune précaution n'a été prise pour l'arrêter.
Les threads utilisateurs se finissent lorsque les instructions au sein de leur méthode run() sont toutes exécutées.
La méthode stop() est à prohiber pour stopper un thread. Cette méthode a été dépréciée en raison des risques qu'elle engendre. En effet, des blocages sévères (deadlock) ou des incohérences de données peuvent survenir suite à l'emploi de cette méthode. En outre, l'appel de la méthode stop() sur un objet Thread peut entraîner la levée d'une erreur ThreadDeath, qu'il est très difficile de gérer correctement.
De la même façon, la suspension et la reprise d'un thread ne peuvent être accomplis respectivement par les méthodes suspend() et resume(). Ces fonctionnalités doivent être programmés d'une manière différente.
Il existe plusieurs solutions pour simuler le fonctionnement des méthodes stop(), suspend() et resume(). L'une d'elles consite à utiliser des champs qui indiqueront au thread comment se comporter.
Exemple [voir]import java.awt.*; import java.awt.event.*; import javax.swing.*; public class AppliCompteur extends JPanel implements Runnable { private Thread threadEnCours; private JTextField txtCompteur; //Champs concourrant à remplacer les méthodes dépréciées //suspend(), resume() et stop() private volatile boolean demarre; private volatile boolean suspension; private volatile boolean arret; public AppliCompteur() { demarre = true; arret = true; txtCompteur = new JTextField(); txtCompteur.setEditable(false); JButton btnSuspension = new JButton("Suspendre"); JButton btnReprendre = new JButton("Reprendre"); JButton btnDemarrer = new JButton("Démarrer"); JButton btnSortir = new JButton("Sortir"); btnSuspension.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { suspendre(); } }); btnReprendre.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { reprendre(); } }); btnDemarrer.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { demarrer(); } }); btnSortir.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { sortir(); } }); this.setLayout(new GridLayout(5, 1, 3, 3)); this.add(txtCompteur); this.add(btnDemarrer); this.add(btnSuspension); this.add(btnReprendre); this.add(btnSortir); } private void suspendre() { suspension = true; } private void reprendre() { suspension = false; } private void demarrer() { if(demarre) arret = false; } public void sortir() { arret = true; if (threadEnCours != null) { threadEnCours.interrupt(); } System.exit(0); } private void attendreSuspension() throws InterruptedException { while (suspension) { Thread.sleep(200); } } private void attendreDemarrage() throws InterruptedException { while (demarre && arret) { Thread.sleep(200); } demarre = false; } public void run() { try { threadEnCours = Thread.currentThread(); //Attendre jusqu'à activation du bouton Démarrer attendreDemarrage(); int compteur = 1; //Continuer tant que le bouton Sortir n'a pas été activé while (!arret) { txtCompteur.setText(String.valueOf(compteur)); Thread.sleep(500); if(compteur % 10 == 0) compteur = 1; else compteur++; //Attendre jusqu'à activation du bouton Suspendre attendreSuspension(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { threadEnCours = null; } } public static void main(String[] args) { AppliCompteur appli = new AppliCompteur(); Thread t = new Thread(appli); t.start(); JFrame f = new JFrame("Démonstration"); f.setContentPane(appli); f.pack(); f.setVisible(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } } |