gif animé ordinateur

jeudi 27 janvier 2011

les threads en java

Pour illustrer les threads en java, imaginons  une application boursière avec plusieurs fonctionnalités et préoccupation. Une d’elles, par exemple, se charge de fournir le prix de la dernière action, la seconde effectue les vérifications et lance les warnings si le prix des actions, tandis que la troisième fournie l’historiques des opérations boursière pour la company XYZ.
Dans un environnement mono thread, ces actions s’exécutent l’une suivi de la suivante dans l’ordre. L’action suivante ne peut s’exécuter qu’une fois la première est achevée. Si par exemple l’analyse de l’historique des données de la company XYW prend ½ heure, les warnings sur les prix des actions ne sont levées qu’une ½ plus tard, et le donneur d’ordre de validation d’achat, de vente ou d’acquisition d’actions ne reçoit l’ordre qu’une fois tous ces process terminés. Je vous laisse imaginer ce que cela peut induire en perte de réactivité et de temps de réponse.
Alors, pour remédier à la situation, on a tout simplement imaginé le monde mutithread. Ainsi, l’application d’analyse de l’historique des données de la company XYZ, tourne en arrière plan dans son propre thread, en simultané avec l’application qui lance les warnings sur les prix des actions sur un autre thread. Nous voila donc entrain de travailler dans un environnement bi-thread.
Mais alors, Un thread, c’est quoi exactement ?
En java, Thread signifie deux choses :
-          Une instance de la classe java.lang.Thread
-          Un autre thread d’exécution

Une instance de Thread, c’est juste un …Object, comme tout autre Object en Java, il a des variables et des méthodes et vit et meurt dans le Heap. Mais un thread  (avec T en minuscule) d’exécution c’est un process individuel ( a lightweight process) qui a son propre appel de la Stack.
En java, il y un thread par appel de la Stack, ou pour le dire autrement un appel de la Stack par thread. Bien que vous ne créiez aucun thread dans vos programme, il y’en a un à chaque exécution.
La méthode java main()  qui se lance et exécute votre programme, lance son propre thread, appelé d’ailleurs main thread. Et quand vous regardez dans la stack traces de l’exécution du programme, vous constatez que la méthode main est le point d’enter dans la stack, et au fur et à mesure qu’on crée d’autre thread, les stack trace s’ajoute l’une derrière l’autre.

Vous pouvez trouvez ça confus, de parler programmes se lançant en parallèle les uns avec les autres dans un OS qui tourne souvent avec un seul CPU. On effet les JVM actuellement sur les OS du marché, se compte comme des mini OS qui ordonnance chacun ses taches selon le type de system en question (MAC, Windows, LINUX …etc.).

Ne faites donc pas l’erreur de concevoir vos applications en fonction de la JVM installée sur votre OS. Les JVM n’ordonnancent pas les thread de la même manière.
En java, les thread se lancent comme des instances de la classe Thread (avec T majuscule). Dans cette classe, des méthodes de gestion de la vie d’un thread sont disponibles, notamment, pour créer, lancer et mettre en pause le thread en cours de création :
- start()
- yield()
- sleep()
- run()

L’exécution est effectue dans la méthode run().
Pensez au thread comme l’agent qui va exécuter votre job (programme). If the work to do is the job, the one doing the work (actually executing the job code) is the thread. And the job always starts from a run() method.

Voici un bout de code pour illustrer ça :

Public void run() {
// your job codes goes here
}

Vous pouvez définir et instancier des threads, de deux façons :
-          en étendant (extends) la classe java.lang.Thread
-          en implémentant (impements)  l’interface Runnable
Dans la vraie vie, vous allez plus implémenter l’interface Runnable qu’étendre la classe java.lang.Thread (T en majuscule).
Etendre la classe Thread est portant très facile à mettre en œuvre par le code, mais cette option n’est pas toujours conforme aux normes de programmation Orientée Object (OO).
En effet le cas où étendre la classe Thread a des sens, est lorsque vous avez plusieurs comportements de votre même thread. Mais heureusement, dans la vraie vie, un job, c’est un thread, et dans ce cas, il est plus commode d’écrire vos thread en les faisant implémenter de l’interface Runnable, qui laisse le libre choix à vos classes d’étendre d’autres classes.
(Une classe ne peut étendre qu’une autre classe, tandis qu’elle peut implémenter autant d’interface qu’elle veut).

Voici un exemple :
Class MyThread extends Thread {
public void run(){
     System.out.println(“ ici est executer mon thread “) ;
}
}

La limite de cette architecture, en plus de son faible respect du concepts de l’OO, et que votre classe ne peut plus étendre aucune autre classe, et ce n’est pas le meilleur pour hériter des comportement d’autres thread.

Dites vous que vous pouvez overloader le méthode run(), mais celle-ci sera ignorée par la classe Thread, sauf si vous la faite appeler vous même.

Class MyThread extends Thread {
public void run(){
     System.out.println(“ ici est executé mon thread “) ;
}
public void run(String s){
     System.out.println(“ string in run is “+s) ;
}
}

La classe Thread ne s’attend et n’appelle que la méthode run() sans arguments, et va exécuter pour vous celle-ci dans une stack à part une fois le thread lancé.

Maintenant, voyons, comment implémenter l’interface Runnable

Class MyRunnable implements Runnable {
public void run(){
     System.out.println(“ important job is runnig in runnable “) ;
}
}

Pour instancier un thread :
Si vous étendez la classe Thread, il vous suffit d’écrire :

MyThread t = new MuThread() ;

En revanche, si vous implémenter l’interface Runnable :
MyRunnable r = new MyRunnable() ;//instantiate your Runnable
Thread t = new Thread(r);//pass your runnable to Thread

Si vous créez votre Thread sans lui passer en argument votre Runnable, la classe Thread appel sa propre méthode run(), c’est ce que vous faite lorsque vous étendez la classe Thread, contrairement à lorsque vous implémenter l’interface Runnable où vous devrez indiquer à votre new thread, la méthode run() à appeler à la place de la sienne.
On peut passer un single Runnable à autant de multiples Thread :

Public class TestThreads{
Public static void main(String[] args){
MyRunnable r = new MyRunnable();
Thread foo = new Thread(r);
Thread bar= new Thread(r);
Thread bat = new Thread(r);

}
}

Passer le même argument à différent Threads, revient à exécuter plusieurs fois le même job.

En plus du constructeur new Thread() sans argument ou avec Runnable comme argument, des overload de celle-ci existent, notamment :
-          Tread(Runnable r, String name)
-          Thread(String name)

Une fois l’object Thread est crée, et que sa cible est connu (l’argument Runnable ), allons y lancer notre thread (lancer à new stack), grâce à la méthode start() :

class FooRunnable impements Runnable {
public void run(){
For(int x=; x<6, x++){
System.out.println(“runnable running”);
}
}
}


Public class TestThreads{
Public static void main(String[] args){
FooRunnable r = new FooRunnable ();
Thread t = new Thread(r);
t.start();

}
}

Voici comment on lance notre thread.
Bonne lecture.

La suite de cet article sera bientôt publiée.




Aucun commentaire:

Enregistrer un commentaire