Le fonctionnement des threads passe par plusieurs étapes décisives. En effet, une unité d'exécution peut prendre plusieurs états distincts dans son cycle de vie.
En premier lieu, une sous-classe héritant de Thread permet de créer une nouvelle unité d'exécution.
L'appel de la méthode start() provoque la mise en état d'exécutable du nouveau thread. Si d'autres threads sont déjà dans cet état, alors le nouveau thread passe en file d'attente des exécutables jusqu'à ce qu'arrive son tour de devenir le thread courant. Eventuellement, une préemption autorise les nouvelles unités d'exécution de priorité élevée, à prendre le pas sur celles de basse priorité. En cas d'égalité, la position des threads dans la file d'attente, déterminera leur ordre d'exécution, c'est-à-dire que le premier passera d'abord.
L'appel de la méthode yield() constitue l'un des moyens de permutation d'unités d'exécutions, en entraînant la mise en file d'attente du thread courant et en donnant la main à un autre thread en attente.
L'utilisation des méthodes sleep() contraint le thread courant à se mettre en pause afin que d'autres threads prennent le contrôle. Pendant cette période, l'ancien thread courant est bloqué. Au terme de la pause, l'unité d'exécution rejoint la file d'attente des exécutables avant de prendre à nouveau la main lorsqu'il y sera autorisé.
/** * La classe Pause permet d'insérer * une pause dans le thread courant. */ public class Pause { public static void ralentir() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } public static void ralentir(long s) { try { Thread.sleep(s * 1000); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * La classe Application utilise une pause * lors du déroulement du programme. */ public class Application { public static void main(String[] args) { int temps = 0; System.out.println("Début des traitements..."); while(temps < 60){ System.out.println("Un traitement quelconque..."); temps += 3; Pause.ralentir(3); } System.out.println("Fin des traitements..."); } }
En outre, un thread courant ou exécutable peut être bloqué suite à l'invocation de la méthode suspend() et ne rejoindra la file d'attente des exécutables qu'à partir du moment où la méthode resume() sera appelée.
La mise en état d'attente d'un thread se produit lors de l'appel de la méthode wait(). Cet état peut durer pendant un certain temps ou jusqu'à ce que soit invoquée l'une des méthodes suivantes : notify() ou notifyAll().
Enfin, un thread devient mort dans le cas où la méthode stop() est appelée à partir d'un thread dans l'état nouveau, exécutable ou actif. Arrivé au terme de la méthode run(), l'unité d'exécution meurt également.
public class Arret implements Runnable { public static void main(String[] args) { Arret arret = new Arret(); Thread thread = new Thread(arret); System.out.println("Démarrage du thread..."); thread.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // Arrêt du thread par une méthode dépréciée thread.stop(); } public void run() { int compteur = 0; while (true) { System.out.println("Compteur = " + compteur); compteur++; try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Toutes les méthodes concourant au cycle de vie d'un thread possède des caractéristiques différentes, si bien que certaines peuvent être directement utilisées dans la sous-classe de Thread (méthodes statiques : yield(), sleep(), wait()) et d'autres seulement à partir de l'instance de la classe étendue (start(), stop(), suspend(), resume(), ...).
Par ailleurs, bien que les méthodes stop(), suspend() et resume() existent, il est fortement déconseillé de les utiliser car elles peuvent occasionner de graves dysfonctionnements de l'application. La mort d'un thread entraîne une impossiblité de connaître ce qu'il faisait juste avant cet instant . Si cela intervenait en pleine sauvegarde d'un objet, alors ce dernier risquerait de devenir incohérent, et partant, illisible par la machine virtuelle alors dans l'incapacité de continuer le déroulement du programme.
Exemple [voir]import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JTextField; public class Application extends JFrame implements Runnable { private Thread thread_principal; private JTextField txtLettre; private JButton btnSuspendre; private JButton btnReprendre; private JButton btnArreter; private JButton btnQuitter; public static void main(String[] args) { Application application = new Application(); Thread thread = new Thread(application); thread.start(); } public Application() { super("Démonstration - suspend(), resume() et stop()"); this.initialiser(); } public void run() { try { thread_principal = Thread.currentThread(); int compteur = 0; while (true) { if(compteur > 25) compteur = 0; txtLettre.setText(String.valueOf((char)('A' + compteur++))); Thread.sleep(300); } } catch (InterruptedException e) { e.printStackTrace(); } finally { thread_principal = null; } } private void suspendre() { if (thread_principal != null) { thread_principal.suspend(); } } private void reprendre() { if (thread_principal != null) { thread_principal.resume(); } } private void arreter() { if (thread_principal != null) { thread_principal.stop(); } } private void quitter() { this.arreter(); thread_principal = null; System.exit(0); } private void initialiser() { this.initPanneau(); this.initFenetre(); } private void initPanneau() { txtLettre = new JTextField(); txtLettre.setEditable(false); txtLettre.setFont(new Font("Verdana", Font.BOLD, 72)); txtLettre.setHorizontalAlignment(JTextField.CENTER); btnSuspendre = new JButton("Suspendre"); btnSuspendre.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { suspendre(); } }); btnReprendre = new JButton("Reprendre"); btnReprendre.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { reprendre(); } }); btnArreter = new JButton("Arrêter"); btnArreter.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { arreter(); } }); btnQuitter = new JButton("Arrêter"); btnQuitter.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { quitter(); } }); GridBagLayout gbl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); JPanel pan = (JPanel)this.getContentPane(); pan.setLayout(gbl); placerComposants(pan, gbl, gbc, txtLettre, GridBagConstraints.BOTH, 0, 0, 4, 1, 1, 1, 3, 3, 3, 3); placerComposants(pan, gbl, gbc, btnSuspendre, GridBagConstraints.BOTH, 0, 1, 1, 1, 1, 0, 3, 3, 3, 3); placerComposants(pan, gbl, gbc, btnReprendre, GridBagConstraints.BOTH, 1, 1, 1, 1, 1, 0, 3, 3, 3, 3); placerComposants(pan, gbl, gbc, btnArreter, GridBagConstraints.BOTH, 2, 1, 1, 1, 1, 0, 3, 3, 3, 3); placerComposants(pan, gbl, gbc, btnQuitter, GridBagConstraints.BOTH, 3, 1, 1, 1, 1, 0, 3, 3, 3, 3); } private void initFenetre() { Dimension tailleFenetre = this.getSize(); Dimension tailleEcran = Toolkit.getDefaultToolkit().getScreenSize(); if (tailleFenetre.height > tailleEcran.height) tailleFenetre.height = tailleEcran.height; if (tailleFenetre.width > tailleEcran.width) tailleFenetre.width = tailleEcran.width; this.setBounds(tailleEcran.width / 3, tailleEcran.height / 3, (tailleEcran.width * 1) / 3, (tailleEcran.height * 1) / 3); this.setVisible(true); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } public void placerComposants( JPanel pere, GridBagLayout gbl, GridBagConstraints gbc, JComponent composant, int remplissage, int x, int y, int l, int h, double px, double py, int haut, int gauche, int bas, int droite){ gbc.insets = new Insets(haut, gauche, bas, droite); gbc.fill = remplissage; gbc.gridx = x; gbc.gridy = y; gbc.gridwidth = l; gbc.gridheight = h; gbc.weightx = px; gbc.weighty = py; gbl.setConstraints(composant, gbc); pere.add(composant); } } |