td/tp miage3, threads java

publicité
TD/TP Miage3, 2005-2006
T D / TP M I A G E 3 , T H R E A D S J A V A
L’objectif de ce TD/TP est de vous faire programmer des threads en Java, de vous faire
observer le comportement des programmes à activités parallèles (multi-threadés) et de vous
montrer le besoin de synchronisation entre threads.
1 IMPLÉMENTATION DES THREADS EN JAVA
Les threads Java peuvent être implémentés de deux manières. La première est d’étendre la
classe prédéfinie Thread:
//classes et interfaces prédéfinies Java, JDK
interface Runnable {
void run();
}
public class Thread
extends Object
implements Runnable {
void run() {...}
void start() {...}
...
}
public class Compteur extends Thread {
public void run() {...}
}
public static main() {
Compteur c = new Compteur();
c.start();
}
}
L’héritage à partir de Thread est contraignant car il empêche tout autre héritage.
Deuxième manière de faire: implémenter l’iterface Runnable et de cette manière avoir la
possibilité d’héritage et d’implémentation d’autres interfaces.
.//classes et interfaces prédéfinies Java, JDK
interface Runnable {
void run();
}
public class Thread
extends Object
implements Runnable {
void run() {...}
void start() {...}
...
}
public class Compteur implements Runnable{
public void run() {...}
}
public static main() {
Compteur c = new Compteur();
new Thread(c).start();}
}
1
TD/TP Miage3, 2005-2006
2 EXERCICES
Les programmes Java pour ce TD/TP se trouvent dans le placard electronique.
http://www-ufrima.imag.fr/placard/INFO/miage3/SR/TDTP1
2.1
PROGRAMME
EXEMPLETHREAD1.JAVA
Compiler et exécuter le programme exempleThread1.java (pour exécuter plusieurs fois, il
est possible d’utiliser exec.sh qui est fourni)
Le programme crée trois threads qui affichent respectivement “Hello” “World” et “and
Everybody”. Que pouvez-vous dire à propos de l’ordre de l’affichage? Expliquer.
Le programme utilise le héritage de Thread pour coder les threads. Changer le code pour
utiliser l’interface Runnable.
2.2
PROGRAMME
EXEMPLETHREAD2.JAVA
Compiler et exécuter plusieurs fois le programme exempleThread2.
Voyez-vous tous les affichages? Essayez d’augmenter les valeurs d’attente (le arguments
passés lors de la création des threads qui sont utilisés pour les appels à sleep). Si vous mettez
de trop grandes valeurs, vous risquez de ne plus voir aucun affichage. Pourquoi?
2.3
EXEMPLETHREAD3.JAVA
Dans ce programme, nous rajoutons la fonction join qui force le programme principal
d’attendre la terminaison des threads. Cimpiler le programme, exécuter plusieurs fois et
s’assurer que tous les affichages sont présents.
2.4
PROGRAMME
MULTI-TÂCHE SIMPLE
En s’inspirant des exemples précédents, ecrire une classe Compte pour la gestion de
comptes. Définir des méthodes pour créditer, débiter et consulter le compte. Ecrire également
une classe de thread CompteModifier (en utilisant l’interface Runnable) qui prend en paramètre un compte et qui modifie son solde. Ecrire un programme principal qui crée un compte,
qui crée plusieurs threads CompteModifier en leur passant en paramètre le compte créé.
Tester, exécuter, observer. Le programme a-t-il le comportement souhaité?
2.5
EXEMPLETHREAD4.JAVA
Dans ce programme, nous manipulons une variable partagée de type Compte. On peut
déposer de l’argent sur le compte ou retirer de l’argent. Le programme principal crée 20
threads ThreadDeposer qui déposent la même somme (10000, puisqu’ils deposent 1000 fois
2
TD/TP Miage3, 2005-2006
10), ainsi que 20 threads ThreadRetirer qui retirent cette même somme. Le résultat à la fin
(compte.consulter()) doit donner 0.
Compiler et exécuter plusieurs fois le programme (en utilisant exec.sh). Y a-t-il des cas où
le résultat est différent? Expliquer.
2.6
EXEMPLETHREAD5.JAVA
Pour corriger le problème dans l’exemple précedent, on définit les deux méthodes
deposer et retirer en tant que synchronized. Compiler et exécuter le programme.
S’assurer que le comportement est correct.
3
TD/TP Miage3, 2005-2006
ANNEXE : RAPPELS SUR LA PROGRAMMATION JAVA
2.7
CLASSES,
INSTANCIATION, OBJETS, MAIN
Java est un langage pour la programmation orientée-objet (OO). La programmation par
objets permet de structurer les programmes non en termes de fichiers, de modules, de fonctions
et de procédures, mais en termes de structures (les objets) qui modélisent les choses du monde
réel.
Exemple : vous voulez modéliser une voiture, vous allez définir une structure “Voiture”. La
voiture a quatre roues, un volant, quatre portes, deux sièges avant, deux sièges arrière, etc : vous
allez définir, à l’intérieur de la structure “Voiture” d’autres structures pour les différentes parties
de la voiture. La voiture peut démarrer, s’arrêter, prendre de l’essence, avoir un accident : vous
aller définir des actions pour manipuler la structure “Voiture”. Dans votre programme vous
allez vouloir gérer différentes voitures (vous êtes vendeur de voitures), alors il va falloir pouvoir
créer et manipuler différentes structures “Voiture”.
Pour faire ceci en Java, nous allons définir une classe Voiture qui va définir la structure générique d’une voiture. Dans cette classe, nous allons définir des attributs pour dire
quelles sont les parties d’une voiture. Nous allons également définir des méthodes pour les
différentes actions que nous pouvons faire avec une voiture. Ce qui nous donne :
class Voiture {
//attributs
Roue roueAvG, roueAvD, roueArG, roueArD;
Volant volant;
Siege sieges[4];
String marque;
int nbKilometres;
int litresEssence;
String étatVoiture;
...
//méthodes
void démarrer() {étatVoiture=”démarré”;}
void arrêter() {étatVoiture=”arrêté”;}
...
}
Le programme principal (celui qui est exécuté lorsqu’on lance le programme Java), est
contenu dans une méthode main, définie également dans une classe. Par exemple, si nous avons
un magasin de voitures, nous pouvons définir une classe Magasin. Dans cette classe Magasin
nous voyons que la création de voitures se fait à l’aide d’une opération spéciale : new. Avec
cette opération on appelle une méthode spéciale de la classe Voiture, son constructeur. Si
on peut dire que la classe Voiture définit un type (qqchose d’abstrait), quand on appelle son
constructeur nous créons un objet concret qui peut être manipulé dans le programme. On dit
que la classe est instanciée.
class Magasin {
//attributs
Voiture[100] stock;
int nbVoitures;
...
4
TD/TP Miage3, 2005-2006
//méthodes
void recevoirVoiture(int kilometres, int essence, String marque) {
nbVoitures++;
Voiture nouvelle = new Voiture (kilometres, essence, marque);
stock[nbVoitures]=nouvelle;
}
void vendreVoiture(int numero) {
for (int i = numero; i < nbVoitures-1; i++)
stock[i]=stock[i+1];
nbVoitures--;
}
...
//programme principal
void main() {
while true() {
System.out.println(“Menu principal\n“+
“1 : recevoir Voiture\n” +
“2 : vendre Voiture\n”+
...);
...
//création de voiture
if (choix==1) {
...
recevoirVoiture(...);
}
}
}
Le constructeur dans la classe Voiture est défini comme suit:
class Voiture {
String marque;
int nbKilometres;
int litresEssence;
...
Voiture (int k, int e, String m) {
marque = m;
nbKilometres = k;
litresEssence=e;
}
...
}
2.8
COMPILATION
ET EXÉCUTION
Pour compiler notre programme Java: javac Voiture.java Magasin.java
Pour exécuter: java Magasin //la classe qui contient le main
On peut compiler les classes Java séparemment. Dans ce cas, il faut indiquer au compilateur
où il peut trouver les classes qui sont référencées dans les classes que l’on est en train de
compiler. Pour cela,on utilise le classpath.
5
TD/TP Miage3, 2005-2006
Par exemple:
javac Voiture.java //crée Voiture.class ds répértoire courant
javac -classpath . Magasin.java
Pour créer les classes non dans le répertoire courant mais dans un répértoire destination:
avac -d dest Voiture.java //crée Voiture.class ds dest
javac -classpath destination Magasin.java
La compilation d’une classe Java ne génère pas de langage machine (compréhensible par
le processeur de la machine sur laquelle on travaille) mais crée un format intermédiare qui est
interprête avant d’être exécuté sur le processeur. L’interprétation est faite par la machine
virtuelle Java (JVM). L’avantage est que tout programme Java peut être exécuté sur les
machines où est installée la machine virtuelle (portabilité et indépendance du matériel). Toutefois, si un nouveau matériel doit être pris en compte, la machine virtuelle doit être réécrite.
Source .java
javac
compilation
bytecode
JVM
Machine physique
2.9
AUTRES
2.9.1. Héritage
Imaginons que le magasin ne vend pas uniquement des voitures, mais également des
cmaions. Dans ce cas on voudrait avoir une entité générique Vehicule (on aura toujours quatre
roues, une marque, avoir les mêmes actions). Par contre pour les véhicules on voudrait spécifier
PermisB, alors que pour les camions PermisC.
class Vehicule {
Roue ...
Volant
int nbKilometres;
int litresEssence
String marque
void démarrer()...
void arrêter()
...
}
class Voiture extends Vehicule {
String permis;
Voiture(...) {
super();
permis=”B”;
}
}
class Camion extends Vehicule {
6
TD/TP Miage3, 2005-2006
String permis;
Voiture(...) {
super();
permis=”C”;
}
}
La class Voiture hérite de Vehicule, ce qui veut dire qu’elle dispose des attributs et des
méthodes définis dans Vehicule (réutilisation de code).
2.9.2. Accès aux attributs et aux méthodes
Specifier
Class
Package
Subclass
World
private
Y
N
N
N
no specifier
Y
Y
N
N
protected
Y
Y
Y
N
public
Y
Y
Y
Y
2.9.3. static
Les attributs et les méthodes static caractérisent les classes Java et non les objets. Ils sont
utilisés en mettant le nom de la classe, point, le nom de la méthode /de l’attribut
public class HelloWorld {
//calcul de la moyenne de valeurs entières
public static sayHelloWorld(String person) {
System.out.println(pesron + «says Hello World!»);
}
public class MainCalss {
public static void main() {
HelloWorld.sayHelloWorld(«Olivier»);
}
}
2.9.4. Interfaces
Mêmes fonctions, différentes implémentations.
interface SommeProduit{
int somme();
int produit();
}
class Doublet implements SommeProduit{
int a, b;
...
public int somme(){return a + b;}
public int produit(){return a * b;}
}
class Triplet implements SommeProduit{
int a, b, c;
...
7
TD/TP Miage3, 2005-2006
public int somme(){return a + b +c;}
public int produit(){return a * b *c);
2.10 EXCEPTIONS
Les exceptions servent à traiter les erreurs en Java. Dans le JDK (Java Development Kit),
les classes prédéfinies viennent avec une définition des erreurs possibles i.e avec des execptions
prédéfinies. Pour cette raison, il existe des méthodes définies de la manière suivante :
public static Object get(Object array,
int index)
throws IllegalArgumentException,
ArrayIndexOutOfBoundsException
Toutes les exceptions héritent de la classe Exception. Pour traiter une exception, il faut
utiliser un bloc try-catch. Par exemple, si on appelle la méthode get précédente, il faudrait écrire
un code de ce genre:
try {
get(array,10);
} catch (ArrayIndexOutOfBoundsException e) {
/*traiter exception...*/
...
} catch (IllegalArgumentException e){
...
}
Si on ne veut pas traiter les diféfrentes execptions une à une, on peut écrire
try {
...
} catch (Exception e) {
}
8
Téléchargement