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
//: CompteurNA.java
// A non-responsive user interface //package c14; import java.awt.*; import java.awt.event.*; import java.applet.*; public class CompteurNA extends Applet {
|
|
class StartL implements ActionListener {
public void actionPerformed(ActionEvent e) {
go();
}
}
class OnOffL implements ActionListener {
public void actionPerformed(ActionEvent e) {
runFlag = !runFlag;
}
}
public static void main(String[] args) {
CompteurNA applet = new CompteurNA();
Frame aFrame = new Frame("CompteurNA");
aFrame.addWindowListener( new
WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(300,200);
applet.init();
applet.start();
aFrame.setVisible(true);
}
}
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().
//: SimpleThread.java public class SimpleThread extends Thread { |
java SimpleThread
|
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().
On peut utiliser un Thread qui travail tous le
temps:
//: CompteurA.java
// Using the Runnable interface to turn the // main class into a thread. import java.awt.*; import java.awt.event.*; import java.applet.*; public class CompteurA extends Applet implements Runnable {
|
|
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 java.applet.*;
public class CompteurA1
extends Applet implements Runnable {
private int count = 0;
private Thread selfThread = null;
private Button
onOff = new Button("Stop"),
start = new Button("Start");
private TextField t = new TextField(10);
public void init() {
add(t);
start.addActionListener(new StartL());
add(start);
onOff.addActionListener(new OnOffL());
add(onOff);
}
public void run() {
while (true) {
try {
selfThread.sleep(100);
} catch (InterruptedException e){}
t.setText(Integer.toString(count++));
}
}
class StartL implements ActionListener {
public void actionPerformed(ActionEvent e) {
if(selfThread == null){
selfThread = new Thread(CompteurA1.this);
selfThread.start();
}
}
}
class OnOffL implements ActionListener {
public void actionPerformed(ActionEvent e) {
if(selfThread != null) {
selfThread.stop();
selfThread = null;
}
}
}
public static void main(String[] args) {
CompteurA1 applet = new CompteurA1();
Frame aFrame = new Frame("CompteurA1");
aFrame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(300,200);
applet.init();
applet.start();
aFrame.setVisible(true);
}
} ///:~
Lancement
de plusieurs threads
//: CompteurPT.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 java.applet.*; class Ticker extends Thread {
|
|
public void stp() {
runFlag = false;
}
public void restart() {
runFlag = true;
}
}
public class CompteurPT extends Applet {
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 boolean isApplet = true;
private int size;
public void init() {
// Get parameter "size" from Web page:
if(isApplet)
size = Integer.parseInt(getParameter("size"));
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) {
CompteurPT applet = new CompteurPT();
// This isn't an applet, so set the flag and
// produce the parameter values from args:
applet.isApplet = false;
applet.size = (args.length == 0 ? 5 :
Integer.parseInt(args[0]));
Frame aFrame = new Frame("CompteurPT");
aFrame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(200, applet.size * 50);
applet.init();
applet.start();
aFrame.setVisible(true);
}
}
Partage des resources
//: Sharing1.java
// Problems with resource sharing while threading
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
class TwoCounter extends Thread {
private boolean started = false;
private TextField
t1 = new TextField(5),
t2 = new TextField(5);
private Label l =
new Label("count1 == count2");
private int count1 = 0, count2 = 0;
// Add the display components as a panel
// to the given container:
public TwoCounter(Container c) {
Panel p = new Panel();
p.add(t1);
p.add(t2);
p.add(l);
c.add(p);
}
public void start() {
if(!started) {
started = true;
super.start();
}
}
public void run() {
while (true) {
t1.setText(Integer.toString(count1++));
t2.setText(Integer.toString(count2++));
try {
sleep(500);
} catch (InterruptedException e){}
}
}
public void synchTest() {
if(count1 != count2)
l.setText("Unsynched");
}
}
class Watcher extends Thread {
private Sharing1 p;
public Watcher(Sharing1 p) {
this.p = p;
start();
}
public void run() {
while(true) {
for(int i = 0; i < p.s.length; i++)
p.s[i].synchTest();
try {
sleep(50);
} catch (InterruptedException e){}
}
}
}
public class Sharing1 extends Applet {
TwoCounter[] s;
private Button
start = new Button("Start");
private boolean isApplet = true;
private int numCounters = 0;
private int numObservers = 0;
public void init() {
if(isApplet) {
numCounters =
Integer.parseInt(getParameter("size"));
}
s = new TwoCounter[numCounters];
for(int i = 0; i < s.length; i++)
s[i] = new TwoCounter(this);
Panel p = new Panel();
start.addActionListener(new StartL());
p.add(start);
add(p);
new Watcher(this);
}
class StartL implements ActionListener {
public void actionPerformed(ActionEvent e) {
for(int i = 0; i < s.length; i++)
s[i].start();
}
}
public static void main(String[] args) {
Sharing1 applet = new Sharing1();
// This isn't an applet, so set the flag and
// produce the parameter values from args:
applet.isApplet = false;
applet.numCounters =
(args.length == 0 ? 5 :
Integer.parseInt(args[0]));
Frame aFrame = new Frame("Sharing1");
aFrame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(300, applet.numCounters *100);
applet.init();
applet.start();
aFrame.setVisible(true);
}
} ///:~