Conceptuellement les threads ressemblent à des processus, à la différence que plusieurs threads partagent le même espace d'adressage, se qui signifie qu'ils peuvent partager des variables et des méthodes (en possédant en même temps ses propres variables locales).
Les threads sont plus économes en ressources si on les compare au processus, donc il est concevable pour une seule application de lancer des centaines de threads en même temps
Мultiprocessing
et Multithreading
Мultiprocessing - deux ou plusieurs programmes qui s'exécutent
"visiblement" de manière compétitive sous le
contrôle du système d'exploitation. Les programmes n'ont
aucun lien entre eux, sauf le fait qu'ils sont démarrés
et exécutés simultanément. Il est mis en
œuvre par le système d'exploitation et aucune mesure ne
doit être prise au sein du programme.
Multithreading - deux ou plusieurs tâches qui sont
effectuées "visiblement" en parallèle dans le même
programme. Parfois appelés processus
« légers »
Bien qu'il nécessite une maintenance du système
d'exploitation, il est implémenté et
exécuté par le programme lui-même. la conception et
la planification de programmes spéciaux sont nécessaires
Caractéristiques
Constructeurs
Thread() Allocates a new Thread object. |
Thread(String name) Allocates a new Thread object.
|
Thread(Runnable target) Allocates a new Thread object.
|
Thread(Runnable target, String name) Allocates a new Thread object.
|
Quelques méthodes utilisées souvent
public
static Thread currentThread() Returns a reference to the currently executing thread object. |
public
final String getName() Returns this thread's name. |
public
final void setName(String name) Changes the name of this thread to be equal to the argument name . |
Dériver la classe Thread
La programmation avec les
threads a des particularités surtout
avec la synchronisation des threads. Java a des utiles simples pour
résoudre
bon nombre de problèmes.
Les threads sont créés et contrôlé par les objets de la classe Thread.
Chaque objet de ce classe correspond à un seul thread. Il contient des méthodes pour lancer, contrôler et arrêter l'exécution du thread. Pour lancer l'exécution d'un thread on doit appeler la méthode start() de la classe Thread. Une fois que le thread est lancé, il continue à s'exécuter jusqu'à la fin du traitement (indiqué par la méthode run() ) ou jusqu'à ce que la méthode stop() le termine.
Le traitement qui doit être effectué par le thread est indiqué par une méthode appelée run(). On a deux possibilités pour spécifier la méthode run(). Premièrement, la classe Thread elle-même possède une méthode run(). On peut dériver la classe Thread et de redéfinir sa méthode run() pour faire ce que l'on veut. Dans ce cas on crée une instance de la classe dérivée et on lance sa méthode start().
Implémenter Runnable
Il n'est pas toujours possible de créer une classe
dérivée de la classe Thread. Par exemple une applet doit
être dérivée de la classe Applet, donc elle ne peut
pas être dérivée en même temps de la classe
Thread.
Dans ce cas on a besoin d'indiquer à la classe Thread quel objet
possède la méthode run() qu'il doit exécuter. La
classe
Thread possède un constructeur qui prend comme argument une
référence
sur un objet. Si on crée un objet thread en utilisant ce
constructeur
et si on appelle sa méthode start() le thread va exécuter
la méthode run() de l'objet passé en paramètre
plutôt
que la sienne. Pour effectuer cette opération, Java a besoin
d'avoir
garantie que l'objet que nous passons en paramètre contient une
méthode run().
Création
o La classe java. lang. Thread permet de créer de nouveaux threads |
Dériver
la
classe Thread
o Méthode 1 : une sous - classe de Thread class
Proc1 extends
Thread { |
Implémenter
Runnable
o Méthode 2 : une classe qui implémente Runnable class
Proc2 implements
Runnable { |
Quelle solution
choisir ?
o Méthode 1 : sous- classer Thread public class MyThreadApplet extends Applet implements Runnable {}
|
3.2 Etats d'un thread (Cycle de vie)
4 états: New , Runnable, Blocked, Dead .
Pour chaque passage dans Blocked il existe une récuperation spécifique: suspend() - resume, wait()-notify() |
Méthode isAlive()
La classe Thread possede un méthode isAlive()
Méthode getState()
Après release 5.0 existe la méthode
Thread.getState()
qui a pour résultat une de
cettes Thread.State
valeurs:
NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED
Dériver la classe Thread
//: SimpleThread.java public class SimpleThread extends Thread { private int countDown = 5; private String name,indent; private static String s=""; public SimpleThread(String nameP) { name = nameP; indent = (s+=" "); System.out.println("Making " + name); } public void run() { for( ;countDown>0; countDown--) { System.out.println(indent+"Thread " + name + "(" + countDown + ")"); } System.out.println(indent+"Thread " + name + " end"); } public static void main(String[] args) { String nameA[]={"Nick", "Marie", "George", "Isabelle", "Pierre"}; for(int i = 0; i < 5; i++) new SimpleThread(nameA[i]).start(); System.out.println("All Threads Started"); } }
|
Making Nick Making Marie Thread Nick(5) Thread Nick(4) Making George Thread Nick(3) Thread Nick(2) Thread Nick(1) Thread Marie(5) Thread Marie(4) Making Isabelle Thread Marie(3) Thread Marie(2) Thread George(5) Thread Nick end Thread George(4) Thread Marie(1) Thread Marie end Making Pierre Thread George(3) Thread Isabelle(5) All Threads Started Thread George(2) Thread Pierre(5) Thread Isabelle(4) Thread Pierre(4) Thread George(1) Thread Pierre(3) Thread Isabelle(3) Thread Pierre(2) Thread Pierre(1) Thread George end Thread Pierre end Thread Isabelle(2) Thread Isabelle(1) Thread Isabelle end |
//: SimpleThread.java public class ST extends Thread { private int countDown = 5; private String name,indent; static private String s=""; public ST(String nameP) { super(nameP); name = nameP; indent= (s+=" "); System.out.println("Making " + name); } public void run() { for( ;countDown>0; countDown--) { System.out.println(indent +"Thread " + name + "(" + countDown + ")"); } System.out.println(indent + "Thread " + name + " end"); } public static void main(String[] args) { String nameA[]={"Nick", "Marie", "George", "Isabelle", "Pierre"}; Thread t[] = new Thread[nameA.length]; for(int i = 0; i < 5; i++){ t[i]=new ST(nameA[i]); for(int j=0;j<=i;j++) System.out.println("\t\tThread " + t[j].getName()+":"+t[j].getState()); t[i].start(); } System.out.println("All Threads Started"); } } |
Making Nick Thread Nick:NEW Making Marie Thread Nick:RUNNABLE Thread Marie:NEW Thread Nick(5) Thread Nick(4) Thread Nick(3) Thread Nick(2) Thread Nick(1) Making George Thread Marie(5) Thread Nick end Thread Marie(4) Thread Nick:BLOCKED Thread Marie(3) Thread Marie:BLOCKED Thread Marie(2) Thread Marie(1) Thread Marie end Thread George:NEW Making Isabelle Thread Nick:TERMINATED Thread Marie:TERMINATED Thread George:RUNNABLE Thread George(5) Thread Isabelle:NEW Thread George(4) Thread George(3) Thread George(2) Making Pierre Thread Isabelle(5) Thread George(1) Thread Isabelle(4) Thread Isabelle(3) Thread Nick:TERMINATED Thread Marie:TERMINATED Thread George:BLOCKED Thread Isabelle:BLOCKED Thread Pierre:NEW Thread Isabelle(2) Thread George end Thread Isabelle(1) Thread Isabelle end All Threads Started Thread Pierre(5) Thread Pierre(4) Thread Pierre(3) Thread Pierre(2) Thread Pierre(1) Thread Pierre end |
Chaque thread a la priorité (le droit de commencer avant les autres). Les priorités sont représentées par des entiers allant de Thread.MAX_PRIORITY (10 - le plus élevé) à Thread.MIN_PRIORITY (1 - le plus bas). Par défaut, chaque thread a la même priorité que celui qui l'a créé. Une fois la priorité du thread créée, vous pouvez la modifier à l'aide de la méthode setPriority ().
//: SimpleThread.java public class St extends Thread { private int countDown = 5; private String name; public St(String nameP) { name = nameP; System.out.println("Making " + name); } public void run() { for( ;countDown>0; countDown--) { System.out.println("Thread " + name + "(" + countDown + ")"+ " priority -> " + getPriority() ); } System.out.println("Thread " + name + " end"); } public static void main(String[] args) { String nameA[]={"Nick", "Marie", "George", "Isabelle", "Pierre"}; for(int i = 0; i < 5; i++) new St(nameA[i]).start(); System.out.println("All Threads Started"); } }
|
Making Nick Making Marie Making George Making Isabelle Making Pierre All Threads Started Thread Marie(5) priority -> 5 Thread Marie(4) priority -> 5 Thread Marie(3) priority -> 5 Thread Marie(2) priority -> 5 Thread Marie(1) priority -> 5 Thread Marie end Thread Isabelle(5) priority -> 5 Thread Isabelle(4) priority -> 5 Thread Pierre(5) priority -> 5 Thread Nick(5) priority -> 5 Thread George(5) priority -> 5 Thread Isabelle(3) priority -> 5 Thread Pierre(4) priority -> 5 Thread Nick(4) priority -> 5 Thread George(4) priority -> 5 Thread Isabelle(2) priority -> 5 Thread Pierre(3) priority -> 5 Thread Nick(3) priority -> 5 Thread George(3) priority -> 5 Thread Isabelle(1) priority -> 5 Thread Pierre(2) priority -> 5 Thread Nick(2) priority -> 5 Thread George(2) priority -> 5 Thread Isabelle end Thread Pierre(1) priority -> 5 Thread Nick(1) priority -> 5 Thread George(1) priority -> 5 Thread Pierre end Thread Nick end Thread George end |
3.3.4 Exemple avec modification des priorités:
import
java.text.*; import java.util.*; //: SimpleThreadPr.java public class SimpleThreadPr extends Thread { private int countDown = 5; private String name; private static Date dt = new Date( ); private static DateFormat df = new SimpleDateFormat("HH:mm:ss:SSS"); private volatile double d=0; // no optimization public SimpleThreadPr(String name, int prior) { this.name = name; setPriority(prior); System.out.println("\t\tMaking " + name); } public void run() { dt.setTime(System.currentTimeMillis( )); System.out.println(name+"start at "+df.format(dt)+"pr -> "+getPriority()); for( ;countDown>0; countDown--) { // An expensive, interruptible operation: for(int i = 1; i < 100000; i++) d = d + (Math.PI + Math.E) / (double)i; System.out.println("Thread " + name + "(" + countDown + ")"+ " priority -> " + getPriority() ); } System.out.println("Thread " + name + " end"); } public static void main(String[] args) { String nameA[]={"Nick", "Marie", "George", "Isabelle", "Pierre","Rose","Salome"}; SimpleThreadPr st[] = new SimpleThreadPr[nameA.length]; for(int i = 0; i < nameA.length; i++) st[i] = new SimpleThreadPr(nameA[i],i<3?Thread.MAX_PRIORITY: Thread.MIN_PRIORITY); for(int i = 3; i < nameA.length; i++) st[i] .start(); System.out.println("\t\tThe Threads with low priority started"); for(int i = 0; i < 3; i++) st[i] .start(); System.out.println("\t\tAll Threads Started"); } }
|
Making Nick Making Marie Making George Making Isabelle Making Pierre Making Rose Making Salome The Threads with low priority started All Threads Started Nickstart at 09:49:37:705pr -> 10 Rosestart at 09:49:37:705pr -> 1 Isabellestart at 09:49:37:705pr -> 1 Pierrestart at 09:49:37:705pr -> 1 Salomestart at 09:49:37:705pr -> 1 Mariestart at 09:49:37:705pr -> 10 Georgestart at 09:49:37:705pr -> 10 Thread Nick(5) priority -> 10 Thread Marie(5) priority -> 10 Thread George(5) priority -> 10 Thread Isabelle(5) priority -> 1 Thread Marie(4) priority -> 10 Thread Pierre(5) priority -> 1 Thread Rose(5) priority -> 1 Thread Salome(5) priority -> 1 Thread George(4) priority -> 10 Thread Nick(4) priority -> 10 Thread Marie(3) priority -> 10 Thread Nick(3) priority -> 10 Thread Rose(4) priority -> 1 Thread Isabelle(4) priority -> 1 Thread Pierre(4) priority -> 1 Thread Marie(2) priority -> 10 Thread George(3) priority -> 10 Thread Nick(2) priority -> 10 Thread Rose(3) priority -> 1 Thread Salome(4) priority -> 1 Thread Isabelle(3) priority -> 1 Thread Marie(1) priority -> 10 Thread Marie end Thread George(2) priority -> 10 Thread Rose(2) priority -> 1 Thread Nick(1) priority -> 10 Thread Nick end Thread Pierre(3) priority -> 1 Thread George(1) priority -> 10 Thread George end Thread Salome(3) priority -> 1 Thread Isabelle(2) priority -> 1 Thread Pierre(2) priority -> 1 Thread Rose(1) priority -> 1 Thread Rose end Thread Pierre(1) priority -> 1 Thread Pierre end Thread Salome(2) priority -> 1 Thread Isabelle(1) priority -> 1 Thread Isabelle end Thread Salome(1) priority -> 1 Thread Salome end |
Remarque: En principe il y a
des différentes approches de combiner "round
robin" avec des priorités dans les différents JVM pour
éviter le risque de "starving". D'une manière
générale, il n'est guère conseillé d'agir
sur les priorités des threads dans les programmes qui se veulent
portables!
Implémenter Runnable
3.3.5 On peut utiliser un Thread qui travail tous le temps:
//: CounterA.java // Using the Runnable interface to turn the // main class into a thread. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class CounterA extends JPanel implements Runnable { private int count = 0; private boolean runFlag = true; private Thread selfThread = null; private Button onOff = new Button("Stop"), start = new Button("Start"); private TextField t = new TextField(10); private Label l = new Label("Thread: no Thread counter yet"); public void init() { add(t); start.addActionListener(new StartL()); add(start); onOff.addActionListener(new OnOffL()); add(onOff); add(l); } public void run() { while (true) { try { Thread.sleep(100); } catch (InterruptedException e){} if(runFlag) { t.setText(Integer.toString(count++)); l.setText("Thread: "+selfThread.getName()); } } } class StartL implements ActionListener { public void actionPerformed(ActionEvent e) { if(selfThread == null){ selfThread = new Thread(CounterA.this); selfThread.start(); } runFlag = true; } } class OnOffL implements ActionListener { public void actionPerformed(ActionEvent e) { runFlag = false; } } public static void main(String[] args) { CounterA cnt = new CounterA(); JFrame frame = new JFrame("CounterA"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(cnt); frame.setSize(300,200); cnt.init(); frame.setVisible(true); } } |
3.3.6. Ou bien créer et tuer le Thread chaque fois:
//: CompteurA1.java // Using the Runnable interface to turn the // main class into a thread. import java.awt.*; import java.awt.event.*; import javax.swing.*; public class CounterA1 extends JPanel implements Runnable { private int count = 0; private Thread selfThread = null; private Button stop = new Button("Stop"), start = new Button("Start"); private TextField t = new TextField(10); private Label l = new Label("Thread: no Thread counter yet"); private boolean runFlag=true; public void init() { add(t); add(l); start.addActionListener(new StartL()); add(start); stop.addActionListener(new StopL()); add(stop); } public void run() { while (runFlag) { try { Thread.sleep(100); } catch (InterruptedException e){} t.setText(Integer.toString(count++)); l.setText("Thread: "+selfThread.getName()); } selfThread = null; } class StartL implements ActionListener { public void actionPerformed(ActionEvent e) { if(selfThread == null){ selfThread = new Thread(CounterA1.this); runFlag=true; selfThread.start(); } } } class StopL implements ActionListener { public void actionPerformed(ActionEvent e) { if(selfThread != null) { // selfThread.stop(); deprecated runFlag =false; } } } public static void main(String[] args) { CounterA1 cnt = new CounterA1(); JFrame aFrame = new JFrame("CounterA1"); aFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); aFrame.add(cnt); aFrame.setSize(300,200); cnt.init(); aFrame.setVisible(true); } } |
3.3.7 Lancement de plusieurs threads
//: CounterPT.java // If you separate your thread from the main // class, you can have as many threads as you want. import java.awt.*; import java.awt.event.*; import javax.swing.*; class Ticker extends Thread { private Button b = new Button("Toggle"); private TextField t = new TextField(10); private int count = 0; private boolean runFlag = true; public Ticker(Container c) { b.addActionListener(new ToggleL()); JPanel p = new JPanel(); p.add(t); p.add(b); c.add(p); } class ToggleL implements ActionListener { public void actionPerformed(ActionEvent e) { runFlag = !runFlag; } } public void run() { while (true) { if(runFlag) t.setText(Integer.toString(count++)); try { sleep(100); } catch (InterruptedException e){} } } public void stp() { runFlag = false; } public void restart() { runFlag = true; } } public class CounterPT extends JPanel { private Button start = new Button("Start"); private Button stop = new Button("Stop"); private Button restart = new Button("Restart"); private boolean started = false; private Ticker[] s; private int size; public void init() { this.setLayout(new FlowLayout()); s = new Ticker[size]; for(int i = 0; i < s.length; i++) s[i] = new Ticker(this); start.addActionListener(new StartL()); add(start); stop.addActionListener(new StopL()); add(stop); restart.addActionListener(new RestartL()); add(restart); } class StartL implements ActionListener { public void actionPerformed(ActionEvent e) { if(!started) { started = true; for(int i = 0; i < s.length; i++) s[i].start(); } } } class StopL implements ActionListener{ public void actionPerformed(ActionEvent e) { for(int i=0;i<s.length;i++) s[i].stp(); } } class RestartL implements ActionListener{ public void actionPerformed(ActionEvent e){ for(int i=0; i< s.length; i++) s[i].restart(); } } public static void main(String[] args) { CounterPT cnt = new CounterPT(); cnt.size = (args.length == 0 ? 5 : Integer.parseInt(args[0])); JFrame aFrame = new JFrame("CounterPT"); aFrame.add(cnt); aFrame.setSize(200*(1+cnt.size/10), 500); aFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cnt.init(); aFrame.setVisible(true); } } |