JavaRush /Blog Java /Random-FR /Vous ne pouvez pas gâcher Java avec un fil de discussion ...
Viacheslav
Niveau 3

Vous ne pouvez pas gâcher Java avec un fil de discussion : partie I – Thèmes

Publié dans le groupe Random-FR

Introduction

Le multithreading est intégré à Java depuis ses débuts. Jetons donc un rapide coup d'œil à ce qu'est le multithreading. Vous ne pouvez pas ruiner Java avec un thread : Partie I - Threads - 1Prenons comme point de départ la leçon officielle d'Oracle : " Leçon : L'application "Hello World! ". Modifions un peu le code de notre application Hello World comme suit :
class HelloWorldApp {
    public static void main(String[] args) {
        System.out.println("Hello, " + args[0]);
    }
}
argsest un tableau de paramètres d'entrée transmis au démarrage du programme. Sauvegardons ce code dans un fichier dont le nom correspond au nom de la classe et à l'extension .java. Compilons à l'aide de l' utilitaire javac : javac HelloWorldApp.java Après cela, appelons notre code avec un paramètre, par exemple Roger : java HelloWorldApp Roger Vous ne pouvez pas ruiner Java avec un thread : Partie I - Threads - 2Notre code a maintenant un sérieux défaut. Si nous ne transmettons aucun argument (c'est-à-dire exécutons simplement Java HelloWorldApp), nous obtiendrons une erreur :
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
        at HelloWorldApp.main(HelloWorldApp.java:3)
Une exception (c'est-à-dire une erreur) s'est produite dans un thread nommé main. Il s'avère qu'il existe des sortes de threads en Java ? C'est ici que commence notre voyage.

Java et les threads

Pour comprendre ce qu'est un thread, vous devez comprendre comment une application Java est lancée. Modifions notre code comme suit :
class HelloWorldApp {
    public static void main(String[] args) {
		while (true) {
			//Do nothing
		}
	}
}
Maintenant, compilons-le à nouveau en utilisant javac. Ensuite, pour plus de commodité, nous exécuterons notre code Java dans une fenêtre séparée. Sous Windows, vous pouvez procéder ainsi : start java HelloWorldApp. Maintenant, à l'aide de l' utilitaire jps , voyons quelles informations Java nous dira : Vous ne pouvez pas ruiner Java avec un thread : Partie I - Threads - 3Le premier numéro est le PID ou Process ID, l'identifiant du processus. Qu'est-ce qu'un processus ?
Процесс — это совокупность codeа и данных, разделяющих общее виртуальное addressное пространство.
A l'aide de processus, l'exécution des différents programmes est isolée les unes des autres : chaque application utilise sa propre zone mémoire sans interférer avec les autres programmes. Je vous conseille de lire l'article plus en détail : « https://habr.com/post/164487/ ». Un processus ne peut pas exister sans threads, donc si un processus existe, au moins un thread existe. Comment cela se produit-il en Java ? Lorsque nous exécutons un programme Java, son exécution commence par le main. Nous entrons en quelque sorte dans le programme, donc cette méthode spéciale mainest appelée le point d'entrée, ou « point d'entrée ». La méthode maindoit toujours être public static voidtelle que la machine virtuelle Java (JVM) puisse commencer à exécuter notre programme. Voir « Pourquoi la méthode principale Java est-elle statique ? » pour plus de détails. Il s'avère que le lanceur Java (java.exe ou javaw.exe) est une application simple (simple application C) : il charge diverses DLL, qui sont en réalité la JVM. Le lanceur Java effectue un ensemble spécifique d'appels Java Native Interface (JNI). JNI est le mécanisme qui relie le monde de la machine virtuelle Java et le monde du C++. Il s'avère que le lanceur n'est pas la JVM, mais son chargeur. Il connaît les commandes correctes à exécuter pour démarrer la JVM. Sait organiser tout l'environnement nécessaire à l'aide des appels JNI. Cette organisation de l'environnement comprend également la création d'un fil principal, généralement appelé main. Pour voir plus clairement quels threads vivent dans un processus Java, nous utilisons le programme jvisualvm , qui est inclus dans le JDK. Connaissant le pid d'un processus, nous pouvons ouvrir les données immédiatement : jvisualvm --openpid айдипроцесса Vous ne pouvez pas ruiner Java avec un thread : Partie I - Threads - 4il est intéressant de noter que chaque thread possède sa propre zone de mémoire distincte allouée au processus. Cette structure de mémoire est appelée pile. Une pile est constituée de frames. Un frame est le point d’appel d’une méthode, point d’exécution. Un cadre peut également être représenté sous la forme d'un StackTraceElement (voir API Java pour StackTraceElement ). Vous pouvez en savoir plus sur la mémoire allouée à chaque thread ici . Si nous regardons l'API Java et recherchons le mot Thread, nous verrons qu'il existe une classe java.lang.Thread . C'est cette classe qui représente un flux en Java, et c'est avec elle qu'il faut travailler. Vous ne pouvez pas ruiner Java avec un fil de discussion : Partie I - Thèmes - 5

java.lang.Thread

Un thread en Java est représenté comme une instance de la classe java.lang.Thread. Il convient de comprendre immédiatement que les instances de la classe Thread en Java ne sont pas elles-mêmes des threads. Il s'agit simplement d'une sorte d'API pour les threads de bas niveau gérés par la JVM et le système d'exploitation. Lorsque nous lançons la JVM à l'aide du lanceur Java, elle crée un thread principal avec un nom mainet plusieurs autres threads de service. Comme indiqué dans le JavaDoc de la classe Thread : When a Java Virtual Machine starts up, there is usually a single non-daemon thread Il existe 2 types de threads : les démons et les non-démons. Les threads démons sont des threads d’arrière-plan (threads de service) qui effectuent certains travaux en arrière-plan. Ce terme intéressant fait référence au « démon de Maxwell », dont vous pouvez en savoir plus dans l’article Wikipédia sur les « démons ». Comme indiqué dans la documentation, la JVM continue d'exécuter le programme (processus) jusqu'à :
  • La méthode Runtime.exit n'est pas appelée
  • Tous les threads non-démons ont terminé leur travail (à la fois sans erreurs et avec exceptions levées)
D'où le détail important : les threads démons peuvent être terminés sur n'importe quelle commande en cours d'exécution. Par conséquent, l’intégrité des données qu’ils contiennent n’est pas garantie. Par conséquent, les threads démons conviennent à certaines tâches de service. Par exemple, en Java, il existe un thread responsable du traitement des méthodes de finalisation ou des threads liés au Garbage Collector (GC). Chaque thread appartient à un groupe ( ThreadGroup ). Et les groupes peuvent s'intégrer les uns aux autres, formant une hiérarchie ou une structure.
public static void main(String []args){
	Thread currentThread = Thread.currentThread();
	ThreadGroup threadGroup = currentThread.getThreadGroup();
	System.out.println("Thread: " + currentThread.getName());
	System.out.println("Thread Group: " + threadGroup.getName());
	System.out.println("Parent Group: " + threadGroup.getParent().getName());
}
Les groupes permettent de rationaliser la gestion des flux et d'en assurer le suivi. En plus des groupes, les threads ont leur propre gestionnaire d'exceptions. Regardons un exemple :
public static void main(String []args) {
	Thread th = Thread.currentThread();
	th.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
		@Override
		public void uncaughtException(Thread t, Throwable e) {
			System.out.println("An error occurred: " + e.getMessage());
		}
	});
    System.out.println(2/0);
}
La division par zéro provoquera une erreur qui sera détectée par le gestionnaire. Si vous ne spécifiez pas le gestionnaire vous-même, l'implémentation du gestionnaire par défaut fonctionnera, ce qui affichera la pile d'erreurs dans StdError. Vous pouvez en savoir plus dans la revue http://pro-java.ru/java-dlya-opytnyx/obrabotchik-neperexvachennyx-isklyuchenij-java/ ". De plus, le fil de discussion a une priorité. Vous pouvez en savoir plus sur les priorités dans le article " Priorité des threads Java en multithreading ".

Créer un fil de discussion

Comme indiqué dans la documentation, nous avons 2 façons de créer un fil de discussion. La première consiste à créer votre héritier. Par exemple:
public class HelloWorld{
    public static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("Hello, World!");
        }
    }

    public static void main(String []args){
        Thread thread = new MyThread();
        thread.start();
    }
}
Comme vous pouvez le voir, la tâche est lancée dans la méthode runet le thread est lancé dans la méthode start. Il ne faut pas les confondre, car... si nous exécutons la méthode rundirectement, aucun nouveau thread ne sera démarré. C'est la méthode startqui demande à la JVM de créer un nouveau thread. L'option avec un descendant de Thread est mauvaise car nous incluons Thread dans la hiérarchie des classes. Le deuxième inconvénient est que nous commençons à violer le principe de « responsabilité exclusive » SOLID, car notre classe devient simultanément responsable à la fois de la gestion du thread et de certaines tâches qui doivent être effectuées dans ce thread. Qui est correct? La réponse réside dans la méthode même runque nous remplaçons :
public void run() {
	if (target != null) {
		target.run();
	}
}
En voici targetquelques-uns java.lang.Runnableque nous pouvons transmettre à Thread lors de la création d’une instance de la classe. Nous pouvons donc faire ceci :
public class HelloWorld{
    public static void main(String []args){
        Runnable task = new Runnable() {
            public void run() {
                System.out.println("Hello, World!");
            }
        };
        Thread thread = new Thread(task);
        thread.start();
    }
}
C'est aussi Runnableune interface fonctionnelle depuis Java 1.8. Cela vous permet d'écrire encore plus joliment le code de tâche pour les threads :
public static void main(String []args){
	Runnable task = () -> {
		System.out.println("Hello, World!");
	};
	Thread thread = new Thread(task);
	thread.start();
}

Total

J'espère donc que cette histoire montre clairement ce qu'est un flux, comment ils existent et quelles opérations de base peuvent être effectuées avec eux. Dans la partie suivante , il convient de comprendre comment les threads interagissent les uns avec les autres et quel est leur cycle de vie. #Viacheslav
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION