Maison >Java >javaDidacticiel >Programmation simultanée Java : Comment utiliser la classe Thread ?

Programmation simultanée Java : Comment utiliser la classe Thread ?

零下一度
零下一度original
2017-06-23 09:16:042019parcourir
Programmation simultanée Java : utilisation de la classe Thread
 
Voici le aperçu de la table des matières de cet article :
1. L'état du fil
2. Changement de contexte
3. Méthodes dans la classe Thread
 
Réimprimé de :
 

1. Statut du fil

 Un fil passe par plusieurs états depuis la création jusqu'à la mort finale. De manière générale, les threads incluent les états suivants : création (nouveau), prêt (exécutable), en cours d'exécution (en cours d'exécution), bloqué (bloqué), temps d'attente, en attente et mort (mort).
 
L'image ci-dessous décrit l'état d'un fil de la création à la mort :

Dans certains didacticiels, les états bloqué, en attente et en attente sont collectivement appelés états de blocage. Cela est également possible, mais ici, je souhaite lier l'état du thread à l'appel de méthode en Java, je combine donc les deux états d'attente. et le temps d'attente s'est séparé.

2. Changement de contexte

 Pour un processeur monocœur (pour un processeur multicœur, cela signifie un seul cœur), le processeur ne peut exécuter qu'un seul thread à la fois. Le passage à l'exécution d'un autre thread tout en exécutant un thread est appelé changement de contexte de thread (il en va de même pour les processus).
 

3. Méthodes dans la classe Thread

En regardant le code source de la classe java.lang.Thread on peut voir :

La classe Thread implémente l'interface Runnable. Dans la classe Thread, il y a certains attributs clés. Par exemple, name est le nom du Thread, qui peut être. spécifié via les paramètres dans le constructeur de la classe Thread, la priorité indique la priorité du thread (la valeur maximale est 10, la valeur minimale est 1, la valeur par défaut est 5), le démon indique si le thread est un démon. thread, et target indique la tâche à exécuter.
 Les méthodes suivantes sont couramment utilisées dans la classe Thread :
Voici plusieurs méthodes liées à l'état d'exécution du thread :
1 ) méthode start
Start() est utilisé pour démarrer un thread Lorsque la méthode start est appelée, le système démarrera un nouveau thread pour effectuer des sous-tâches définies par l'utilisateur. Dans ce processus, les ressources requises seront allouées. au fil correspondant.
2) méthode run
La méthode run() n'a pas besoin d'être appelée par l'utilisateur lorsqu'un thread est démarré via la méthode start, lorsque le thread obtient le temps d'exécution du processeur. entre dans le corps de la méthode d'exécution pour effectuer des tâches spécifiques. Notez que si vous héritez de la classe Thread, vous devez remplacer la méthode run et définir les tâches spécifiques à effectuer dans la méthode run.
 3) méthode sleep
Il existe deux versions surchargées de la méthode sleep :
La veille équivaut à laisser le thread dormir, à remettre le processeur et à laisser le processeur effectuer d'autres tâches.
Mais une chose à noter est que la méthode sleep ne libérera pas le verrou, c'est-à-dire que si le thread actuel détient un verrou sur un objet, les autres threads ne pourront pas accéder à l'objet même si. la méthode sleep est appelée. Cela deviendra clair lorsque vous regarderez l'exemple suivant :
1
2
3
sleep(long millis)     //参数为毫秒
 
sleep(long millis,int nanoseconds)    //第一参数为毫秒,第二个参数为纳秒
123
sleep(long millis) //Le paramètre est millisecondes sleep(long millis,int nanoseconds) //Le premier paramètre est les millisecondes, le deuxième paramètre est les nanosecondes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Test {
     
    private int i = 10;
    private Object object = new Object();
     
    public static void main(String[] args) throws IOException  {
        Test test = new Test();
        MyThread thread1 = test.new MyThread();
        MyThread thread2 = test.new MyThread();
        thread1.start();
        thread2.start();
    } 
     
     
    class MyThread extends Thread{
        @Override
        public void run() {
            synchronized (object) {
                i++;
                System.out.println("i:"+i);
                try {
                    System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");
                    Thread.currentThread().sleep(10000);
                } catch (InterruptedException e) {
                    // TODO: handle exception
                }
                System.out.println("线程"+Thread.currentThread().getName()+"睡眠结束");
                i++;
                System.out.println("i:"+i);
            }
        }
    }
}
123456789101112131415 16 1718192021222324252627282930313233
Test en classe publique {  private int i = 10; private Object object = new Object(); public static void main(String[] args) lance IOException { Test test = new Test(); MyThread thread1 = test.new MyThread(); MyThread thread2 = test.new MyThread(); thread1.start( ); thread2.start(); } @Override public void run() { synchronisé (objet) { i++; System.out .println("i:"+ i); essayez { System. out.println("Thread"+Thread.currentThread().getName()+"Enter sleep state"); Thread.currentThread().sleep(10000); } catch (InterruptedException e) { }            Système .out.println("Thread"+Thread.currentThread().getName()+"Sleep End"); i++; System.out.println("i:"+ i); } } }}
Résultats de sortie :
N'a pas effectué de tâches spécifiques. Ce n'est que lorsque Thread-0 termine l'exécution et que Thread-0 libère le verrou d'objet que Thread-1 commence l'exécution.

Notez que si la méthode sleep est appelée, l'InterruptedException doit être interceptée ou lancée vers la couche supérieure. Lorsque le temps de veille du thread est écoulé, il peut ne pas être exécuté immédiatement car le processeur peut effectuer d'autres tâches à ce moment-là. Donc appeler la méthode sleep équivaut à mettre le thread dans un état bloquant.

 4) Méthode Yield
L'appel de la méthode Yield entraînera le thread actuel à céder les autorisations du processeur et à laisser le processeur exécuter d'autres threads. Elle est similaire à la méthode sleep et ne libère pas le verrou. Cependant, Yield ne peut pas contrôler l'heure spécifique de transfert du CPU. De plus, la méthode Yield ne peut permettre qu'aux threads ayant la même priorité d'avoir la possibilité d'obtenir le temps d'exécution du CPU.
Notez que l'appel de la méthode rendement ne met pas le thread dans l'état de blocage, mais ramène le thread à l'état prêt. Il suffit d'attendre que le temps d'exécution du CPU soit réacquis, ce qui est différent du temps d'exécution du CPU. méthode de sommeil.
5) méthode join
La méthode join a trois versions surchargées :
1
2
3
1
2
3
join()
join(long millis)     //参数为毫秒
join(long millis,int nanoseconds)    //第一参数为毫秒,第二个参数为纳秒
rejoindre()rejoindre(long millis) //Le paramètre est en millisecondesjoin(long millis,int nanoseconds) //Le premier paramètre est en millisecondes, le deuxième paramètre est en nanosecondes
Si la méthode thread.join est appelée dans le thread principal, la méthode principale attendra que le thread du thread termine son exécution ou attendra un certain temps. Si la méthode de jointure sans paramètres est appelée, attendez que le thread termine son exécution. Si la méthode de jointure avec un paramètre de temps spécifié est appelée, attendez un certain événement.
Regardez l'exemple suivant :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Test {
     
    public static void main(String[] args) throws IOException  {
        System.out.println("进入线程"+Thread.currentThread().getName());
        Test test = new Test();
        MyThread thread1 = test.new MyThread();
        thread1.start();
        try {
            System.out.println("线程"+Thread.currentThread().getName()+"等待");
            thread1.join();
            System.out.println("线程"+Thread.currentThread().getName()+"继续执行");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    } 
     
    class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println("进入线程"+Thread.currentThread().getName());
            try {
                Thread.currentThread().sleep(5000);
            } catch (InterruptedException e) {
                // TODO: handle exception
            }
            System.out.println("线程"+Thread.currentThread().getName()+"执行完毕");
        }
    }
}
12345678 9101112131415 1617181920212223242526272829 30
test de classe publique {  public static void main(String[] args) lance IOException { Système .out.println("Enter thread"+Thread.currentThread().getName()); Test test = new Test(); MyThread thread1 = test.new MyThread( ) ; thread1.start(); essayez { System.out.println("Thread"+Thread.currentThread().getName()+"Attendez " );    thread1.join();     System.out.println("Thread"+Thread.currentThread().getName()+"Continuer l'exécution"); 🎜>         } catch (InterruptedException e) {                                                                                                                                                                 🎜> } > entrez le fil de discussion"+Thread.currentThread().getName()); essayez le { fil de discussion. currentThread().sleep(5000); } catch (InterruptedEx ception e ) {                                                                                                                           // TODO : gérer l'exception "); } >}
Résultat de sortie :

On peut voir que lorsque la méthode thread1.join() est appelée, le thread principal sera entrez wait, puis attendez que thread1 termine son exécution avant de continuer.
En fait, l'appel de la méthode join appelle la méthode wait de Object. Cela peut être connu en visualisant le code source :
 

wait. méthode Cela fera entrer le thread dans un état bloqué, libérera le verrou détenu par le thread et remettra les autorisations d'exécution du processeur.
Puisque la méthode wait amènera le thread à libérer le verrou de l'objet, la méthode join amènera également le thread à libérer le verrou détenu sur un objet. L'utilisation spécifique de la méthode wait est donnée dans l'article suivant.
6) méthode d'interruption
Interruption, comme son nom l'indique, signifie interruption. L'appel de la méthode d'interruption seul peut amener le thread à l'état bloqué à lever une exception, c'est-à-dire qu'il peut être utilisé pour interrompre un thread à l'état bloqué. De plus, la méthode d'interruption et la méthode isInterrupted() sont utilisées pour arrêter le thread ; fil en cours d'exécution.
Voici un exemple :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Test {
     
    public static void main(String[] args) throws IOException  {
        Test test = new Test();
        MyThread thread = test.new MyThread();
        thread.start();
        try {
            Thread.currentThread().sleep(2000);
        } catch (InterruptedException e) {
             
        }
        thread.interrupt();
    } 
     
    class MyThread extends Thread{
        @Override
        public void run() {
            try {
                System.out.println("进入睡眠状态");
                Thread.currentThread().sleep(10000);
                System.out.println("睡眠完毕");
            } catch (InterruptedException e) {
                System.out.println("得到中断异常");
            }
            System.out.println("run方法执行完毕");
        }
    }
}
12345678 910111213141516171819202122232425262728
Test en classe publique {                                                                                                                                                       thread = test.new MyThread(); thread.start(); essayez { Thread.currentThread( .sleep(2000);                                                                                                                           la classe MyThread étend le fil de discussion{ @Override public void run() { essayez { System.out.println("Enter Sleep state"); Thread.currentThread().sleep(10000); System.out .println("Veille terminée"); } catch (InterruptedException e) { System.out.println ("" Anomalie obtenue "); } System.out.println 🎜> } }}
Résultat de sortie :

Comme on peut le voir à partir d'ici, le fil interrompu peut être interrompu via la méthode d'interruption. Alors, un thread dans un état non bloquant peut-il être interrompu ? Regardez l'exemple suivant :
corps>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Test {
     
    public static void main(String[] args) throws IOException  {
        Test test = new Test();
        MyThread thread = test.new MyThread();
        thread.start();
        try {
            Thread.currentThread().sleep(2000);
        } catch (InterruptedException e) {
             
        }
        thread.interrupt();
    } 
     
    class MyThread extends Thread{
        @Override
        public void run() {
            int i = 0;
            while(i
                System.out.println(i+" while循环");
                i++;
            }
        }
    }
}
12 345678910111213141516 17181920212223 2425
Test en classe publique {                                                 IOException { Test test = nouveau Test(); Fil de discussion MyThread = test.new MyThread(); thread.start(); essayer {                                                                                            🎜>        thread.interrupt (); ) { int i = 0; While (I & LT; Integer.max_value) { System.out.println (I+"Pendant le cycle" ); 🎜>i++; } } }}
Lorsque vous exécutez ce programme, vous constaterez que la boucle while continuera à s'exécuter jusqu'à ce que la valeur de la variable i dépasse Integer.MAX_VALUE. Par conséquent, l’appel direct de la méthode d’interruption ne peut pas interrompre un thread en cours d’exécution.
Mais si le thread en cours d'exécution peut être interrompu avec isInterrupted(), car appeler la méthode d'interruption équivaut à définir l'indicateur d'interruption sur true, alors vous pouvez interrompre le thread en appelant isInterrupted() pour déterminer si l'interruption le drapeau est défini. Par exemple, le code suivant :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Test {
     
    public static void main(String[] args) throws IOException  {
        Test test = new Test();
        MyThread thread = test.new MyThread();
        thread.start();
        try {
            Thread.currentThread().sleep(2000);
        } catch (InterruptedException e) {
             
        }
        thread.interrupt();
    } 
     
    class MyThread extends Thread{
        @Override
        public void run() {
            int i = 0;
            while(!isInterrupted() && i
                System.out.println(i+" while循环");
                i++;
            }
        }
    }
}
1
2
3
4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyThread extends Thread{
        private volatile boolean isStop = false;
        @Override
        public void run() {
            int i = 0;
            while(!isStop){
                i++;
            }
        }
         
        public void setStop(boolean stop){
            this.isStop = stop;
        }
    }
56789 1011121314151617181920212223 2425
cours public Test {                                                                                                   lance une exception IO{          Test test = new Test( );             MyThread thread = test.new MyThread(); > try { Thread.currentThread().sleep(2000); } catch (InterruptedException e) {       >        thread.interrupt();                                                       public void run( ) { int i = 0; while(!isInterrupted() && i
Lorsque vous l'exécutez, vous constaterez qu'après avoir imprimé plusieurs valeurs , la boucle while arrête l'impression. Cependant, il n'est généralement pas recommandé d'interrompre le thread de cette manière. Généralement, un attribut isStop est ajouté à la classe MyThread pour marquer s'il faut terminer la boucle while, puis la valeur de isStop est déterminée dans la boucle while.
12 345678910 11121314 la classe MyThread étend le fil de discussion{        private volatile boolean isStop = false; while(!isStop ){ i++; } } public void set Stop(boolean stop ){ this.isStop = stop; } }
Ensuite, vous pouvez terminer la boucle while en appelant la méthode setStop à l'extérieur.
7) méthode stop
La méthode stop est une méthode abandonnée et c'est une méthode dangereuse. Parce que l'appel de la méthode stop mettra directement fin à l'appel de la méthode run et générera une erreur ThreadDeath. Si le thread détient un verrou d'objet, le verrou sera complètement libéré, ce qui entraînera un statut d'objet incohérent. Par conséquent, la méthode stop ne sera fondamentalement pas utilisée.
8) méthode destroy
La méthode destroy est également une méthode abandonnée. En principe, il ne sera pas utilisé.
Voici plusieurs méthodes liées aux attributs du fil :
1) getId
Utilisé pour obtenir l'ID du fil
2) getName et setName
Utilisé pour obtenir ou définir le nom du fil de discussion.
 3) getPriority et setPriority
  sont utilisés pour obtenir et définir la priorité des threads.
 4) setDaemon et isDaemon
  sont utilisés pour définir si le thread devient un thread démon et pour déterminer si le thread est un thread démon.
La différence entre les threads démons et les threads utilisateur est que le thread démon dépend du thread qui l'a créé, contrairement au thread utilisateur. Pour donner un exemple simple : si un thread démon est créé dans le thread principal, lorsque la méthode principale aura fini de s'exécuter, le thread démon mourra également. Le thread utilisateur ne le fera pas. Le thread utilisateur continuera à s'exécuter jusqu'à ce qu'il soit terminé. Dans la JVM, un thread garbage collector est un thread démon.
La classe Thread a une méthode statique couramment utilisée currentThread() pour obtenir le thread actuel.
La plupart des méthodes de la classe Thread ont été mentionnées ci-dessus, alors comment les appels de méthode dans la classe Thread provoqueront-ils des changements dans l'état du thread ? L'image suivante est une amélioration par rapport à l'image ci-dessus :

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Article précédent:Quatre façons d'analyser XMLArticle suivant:Quatre façons d'analyser XML

Articles Liés

Voir plus