


Techniques classiques Java pour réaliser le multi-threading et la synchronisation des threads
Cet article vous apporte des connaissances pertinentes sur java, qui présente principalement les problèmes liés au multi-threading et à la synchronisation des threads dans la bibliothèque de classes principale. Examinons-le ensemble, j'espère qu'il sera utile à tout le monde.
Apprentissage recommandé : "Tutoriel vidéo Java"
1 Multi-threading
Processus 1.1
-
Processus : C'est un programme en cours d'exécution
- allocation des ressources et unité indépendante d'appel
- Chaque processus possède son propre espace mémoire et ses propres ressources système
-
Trois caractéristiques du processus
- Indépendance : les processus sont indépendants les uns des autres et ont leurs propres zones de mémoire indépendantes.
- Dynamique : un processus est un programme en cours d'exécution qui occupe dynamiquement des ressources telles que la mémoire, le processeur et le réseau.
- Concurrence : commutation d'interrogation en partage de temps du processeur. servira chaque processus à tour de rôle, car la vitesse de commutation est très rapide, nous donnant le sentiment qu'il est exécuté en même temps. C'est la concurrence (concurrence : plusieurs exécutions en même temps)
1.2 Thread.
-
Thread : Il s'agit d'un flux de contrôle séquentiel unique dans le processus, c'est un chemin d'exécution
- Thread unique : Un processus n'a qu'un seul chemin d'exécution
- Multi-threading : Un processus a plusieurs chemins d'exécution
1.3 Implémentation multi-thread
1.3.1 Méthode 1 : Hériter de la classe Tread
-
Processus :
- 1. 2. Dans MyTread Remplacez la méthode
-
run()
方法 - 3、创建MyTread类的对象
- 4、启动线程:
void start()
run()
dans la classe -
为什么要重写run()方法?
- 因为run()是用来封装被线程执行的代码
-
run()方法和start()方法的区别?
- run():封装线程执行的代码,直接调用,相当于普通方法的的调用
- start():启动线程,然后由JVM调用此线程中的run()方法
范例
MyTread类:
package test;//1、定义一类MyTread继承Tread类public class MyThread extends Thread{ 2、在MyTread类中重写run()方法 @Override public void run() { for(int i=0;i
- 测试类
package test;public class Demo { public static void main(String[] args) { //3、创建MyTread类的对象 MyThread my1 = new MyThread(); MyThread my2 = new MyThread(); //4、启动线程:void start():启动线程,由Java虚拟机调用此线程的run()方法 my1.start(); my2.start(); }}
1.3.2 方式2:实现Runnable接口
-
流程:
- 1、定义一个MyRunnable类实现Runnable接口
- 2、在MyRunnable类中重写
run()
3 Créez un objet de la classe MyTread - 4 Démarrez le fil :
void start()
- .
- Pourquoi est-ce important ? Écrire la méthode run() ?
- Parce que run() est utilisé pour encapsuler le code exécuté par le thread
- Quelle est la différence entre la méthode run() et la méthode start() ?
start() : démarre le thread, puis la JVM appelle la méthode run() dans ce cas.
Exemple
- Classe MyTread :
package test;public class Demo { public static void main(String[] args) { //3、创建MyRunnable类的对象 MyRunnable mr = new MyRunnable(); //4、创建Tread类的对象,把MyRunnable对象作为构造方法的参数// Thread t1 = new Thread(mr);// Thread t2 = new Thread(mr); //Thread(Runnable target,String name) Thread t1 = new Thread(mr,"高铁"); Thread t2 = new Thread(mr,"飞机"); //5、启动线程 t1.start(); t2.start(); }}
package test;public class MyThread extends Thread{ //构造方法添加线程名称 public MyThread(){} public MyThread(String name) { super(name); } @Override public void run() { for(int i=0;i Copier après la connexion Copier après la connexion |
1.3.2 Méthode 2 : Implémenter l'interface Runnable |
---|---|
: | 1. une classe MyRunnable Implémentez l'interface Runnable |
3 Créez un objet de la classe MyRunnable | 4. Créez un objet de la classe Tread et. utilisez l'objet MyRunnable comme paramètre du constructeur |
Avantages : | |
Convient à la situation où le code de plusieurs programmes identiques traite la même ressource, séparer efficacement le code et les données des threads et des programmes, et mieux refléter la théorie de la conception orientée objet | |
1.3.3 Méthode 3 : implémenter l'interface appelable |
- MyThread类
package test;public class MyThread extends Thread{ //构造方法添加线程名称 public MyThread(){} public MyThread(String name) { super(name); } @Override public void run() { for(int i=0;i
- 测试类
package test;public class Demo { public static void main(String[] args) { /* MyThread my1 = new MyThread(); MyThread my2 = new MyThread(); //2,void setName(Stringname) 将此线程的名称更改为等于参数name my1.setName("高铁"); my2.setName("飞机");*/ //3,通过构造方法设置线程名称 //需要自己定义的类中提供此带参构造方法,并通过super访问父类带参构造方法 /*MyThread my1 = new MyThread("高铁"); MyThread my2 = new MyThread("飞机"); my1.start(); my2.start();*/ //4,public static Thread currentThread() 返回对当前正在执行的线程对象的引用(可以返回main()方法中线程) System.out.println(Tread.currentThread().getName()); //main }}
1.5 线程调度
-
线程有两种调度模型
- 分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
- 抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些
Java使用的是抢占式调度模型
假如计算机只有一个CPU, 那么CPU在某一个时刻只能执行条指令, 线程只有得到CPU时间片,也就是使用权,才可以执行指令。所以说多线程程序的执行是有随机性,因为谁抢到CPU的使用权是不一定的
Thread类中设置和获取线程优先级的方法
方法名 | 说明 |
---|---|
public final int getPriority() [praɪˈɔːrəti] | 返回此线程的优先级 |
public final void setPriority(int newPriority) | 更改此线程的优先级 |
- 线程默认优先级是5;线程优先级范围是:1-10
- 线程优先级高仅仅表示线程获取的CPU时间的几率高,但是要在次数比较多,或者多次运行的时候才能看到你想要的效果
package test;public class Demo { public static void main(String[] args) { ThreadPriority tp1 = new ThreadPriority(); ThreadPriority tp2 = new ThreadPriority(); ThreadPriority tp3 = new ThreadPriority(); tp1.setName("高铁"); tp2.setName("飞机"); tp3.setName("汽车"); //1,public final int getPriority() [praɪˈɔːrəti] 返回此线程的优先级// System.out.println(tp1.getPriority()); //5// System.out.println(tp2.getPriority()); //5// System.out.println(tp3.getPriority()); //5 //2,public final void setPriority(int newPriority) 更改此线程的优先级 System.out.println(Thread.MAX_PRIORITY); //10 System.out.println(Thread.MIN_PRIORITY); //1 System.out.println(Thread.NORM_PRIORITY); //5 //设置正确优先级 tp1.setPriority(5); tp2.setPriority(10); tp3.setPriority(1); tp1.start(); tp2.start(); tp3.start(); }}
1.6 线程控制
方法名 | 说明 |
---|---|
static void sleep(long millis) | 使当前正在执行的线程停留(暂停执行)指定的毫秒数 |
void join() | 等待这个线程死亡 |
void setDaemon(boolean on) [ˈdiːmən] | 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机很快将退出 (并不是立刻退出) |
案例:sleep()方法
- 线程类
package test;public class ThreadSleep extends Thread{ @Override public void run() { for(int i=0;i
- 测试类
package test;public class Demo { public static void main(String[] args) { ThreadSleep ts1 = new ThreadSleep(); ThreadSleep ts2 = new ThreadSleep(); ThreadSleep ts3 = new ThreadSleep(); ts1.setName("曹操"); ts2.setName("刘备"); ts3.setName("孙权"); ts1.start(); ts2.start(); ts3.start();// 曹操:0// 孙权:0// 刘备:0// 孙权:1// 曹操:1// 刘备:1// ... }}
案例:join()方法
package test;public class Demo { public static void main(String[] args) { ThreadJoin tj1 = new ThreadJoin(); ThreadJoin tj2 = new ThreadJoin(); ThreadJoin tj3 = new ThreadJoin(); tj1.setName("康熙"); tj2.setName("四阿哥"); tj3.setName("八阿哥"); tj1.start(); //2,void join() 等待这个线程死亡 try { tj1.join(); } catch (InterruptedException e) { e.printStackTrace(); } tj2.start(); tj3.start();// 康熙:0// 康熙:1// 康熙:2// 四阿哥:0// 四阿哥:1// 八阿哥:0// 八阿哥:1// 八阿哥:2// 四阿哥:2// ... }}
案例:setDaemon()方法
package test;public class Demo { public static void main(String[] args) { ThreadJoin tj1 = new ThreadJoin(); ThreadJoin tj2 = new ThreadJoin(); ThreadJoin tj3 = new ThreadJoin(); tj2.setName("关羽"); tj3.setName("张飞"); //设置主线程为刘备 Thread.currentThread().setName("刘备"); //3,void setDaemon(boolean on) 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出 tj1.setDaemon(true); tj2.setDaemon(true); tj1.start(); tj2.start(); for(int i=0;i<h3 id="strong-线程生命周期-strong"><strong>1.7 线程生命周期</strong></h3><p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/331836944d1895cfc26297fee263339c-0.png" class="lazy" alt="Techniques classiques Java pour réaliser le multi-threading et la synchronisation des threads"></p><h3 id="strong-数据安全问题之案例-买票-strong"><strong>1.8 数据安全问题之案例:买票</strong></h3><p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/331836944d1895cfc26297fee263339c-1.png" class="lazy" alt="Techniques classiques Java pour réaliser le multi-threading et la synchronisation des threads"><br><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/331836944d1895cfc26297fee263339c-2.png" class="lazy" alt="Techniques classiques Java pour réaliser le multi-threading et la synchronisation des threads"></p>
-
为什么出现问题?(这也是我们判断多线程程序是否会有数据安全问题的标准)
- 是否是多线程环境
- 是否有共享数据
- 是否有多条语句操作共享数据
如何解决多线程安全问题呢?
基本思想:让程序没有安全问题的环境
-
怎么实现呢?
- 把多条语句操作共享 数据的代码给锁起来,让任意时刻只能有一一个线程执行即可
- Java提供 了同步代码块的方式来解决
1.9 线程同步_同步代码块
- 锁多条语句操作共享数据,可以使用同步代码块实现
- 格式
synchronized(任意对象) { 多条语句操作共享数据的代码}
好处:让多个线程实现先后依次访问共享资源,解决了多线程的数据安全问题
弊端:当线程很多的时候,因为每个线程都会去判断同步上的锁,这是很消耗资源的,无形中降低程序的运行效率
sellTicket类
package test;//1,定义一个类SellTicket实现Runnable接口,里面定义一个成员变量: private int tickets= 100;public class SellTicket implements Runnable{ private int tickets = 100; private Object obj = new Object(); //2,在ellTicket类中重写run0方法实现卖票, 代码步骤如下 @Override public void run() { while(true) { //tickes=100 //t1,t2,t3 //假设t1抢到CPU执行器 synchronized (obj){ //t1进来后把代码锁起来了 if (tickets > 0) { try { Thread.sleep(100); //t1休息100毫秒 } catch (InterruptedException e) { e.printStackTrace(); } //窗口1正在出售第100张票 System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票"); tickets--; //tickets=99 } //t1出来了,锁就被释放了 } } }}
- 测试类
package test;public class SellTicketDemo { public static void main(String[] args) { //创建SellTicket类的对象 SellTicket st = new SellTicket(); //创建三个Thread类的对象,把SellTicket对象作为构造方法的参数,并给出对应的窗口名称 Thread t1 = new Thread(st,"窗口1"); Thread t2 = new Thread(st,"窗口2"); Thread t3 = new Thread(st,"窗口3"); //启动线程 t1.start(); t2.start(); t3.start(); }}
1.10 线程同步_同步方法
- 作用:把出现线程安全问题的核心方法给锁起来,每次只能一个线程进入访问,其他线程必须在方法外面等待
-
同步方法:就是把synchronized关键字加到方法上;锁对象为:
this
- 格式:
修饰符 synchronized 返回值类型 方法名(方法参数) {}
- 格式:
-
同步静态方法:就是把synchronized关键字加到静态方法上面;锁对象为:
类名.class
- 格式:
修饰符 static synchronized 返回值类型 方法名(方法参数) {}
- 格式:
package test;public class SellTicket implements Runnable{//1非静态 private int tickets = 100; private static int tickets = 100; private Object obj = new Object(); private int x = 0; @Override public void run() { while(true) { if(x%2==0) {//1非静态 synchronized (this) { synchronized (SellTicket.class) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票"); tickets--; //tickets=99 } } } else {// synchronized (obj) {// if (tickets > 0) {// try {// Thread.sleep(100);// } catch (InterruptedException e) {// e.printStackTrace();// }// System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");// tickets--; //tickets=99// }// } sellTicket(); } x++; } }//1非静态// private synchronized void sellTicket() {// if (tickets > 0) {// try {// Thread.sleep(100);// } catch (InterruptedException e) {// e.printStackTrace();// }// System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");// tickets--; //tickets=99// }// } private static synchronized void sellTicket() { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票"); tickets--; //tickets=99 } }}
1.11 线程安全的类(了解)
源码中方法都被synchronized修饰
StringBuffer
- 线程安全, 可变的字符序列
- 从版本JDK 5开始,被StringBuilder替代。通常应该使用StringBuilder类, 因为它支持所有相同的操作,但它更快,因为它不执行同步
Vector
- 从Java 2平台v1.2开始,该类改进了List接口, 使其成为Java Collections Framework的成员。 与新的集合实现不同,Vector被同步。 如果不需要线程安全的实现,建议使用ArrayList代替Vector
Hashtable
- 该类实现了一个哈希表,它将键映射到值。任何非null对象都可以用作键或者值
- 从Java 2平台v1.2开始,该类进行了改进,实现了Map接口,使其成为Java Collections Framework的成员。与新的集合实现不同,Hashtable被同步。 如果不需要线程安全的实现,建议使用HashMap代替Hashtable
Collections
类中static <t> List<t> snchronizedList(List<t> list)</t></t></t>
:返回由指定列表支持的同步(线程安全)的列表
package test;import java.util.ArrayList;import java.util.Collection;import java.util.Collections;public class Demo { public static void main(String[] args) { //static <t> List<t> snchronizedList(List<t> list):返回由指定列表支持的同步(线程安全)的列表 Collection<string> list = Collections.synchronizedList(new ArrayList<string>()); /*源码都是返回Synchronized public static <t> List<t> synchronizedList(List<t> list) { return (list instanceof RandomAccess ? new Collections.SynchronizedRandomAccessList(list) : new Collections.SynchronizedList(list)); }*/ }}</t></t></t></string></string></t></t></t>
1.12 Lock锁
- Lock是接口不能直接实例化,采用实现类ReentrantLock来实例化(JDK5以后)
- ReentrantLock构造方法:
方法名 | 说明 |
---|---|
ReentrantLock() | 创建一个ReentrantLock的实例对象 |
- Lock中获得锁和释放锁方法:
方法名 | 说明 |
---|---|
void lock() | 获得锁 |
void unlock() | 释放锁 |
- 推荐使用
try{} finall{}
代码块来加锁和释放锁
package test;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class SellTicket implements Runnable{ private static int tickets = 100; private Lock lock = new ReentrantLock(); @Override public void run() { while(true) { try { lock.lock(); if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票"); tickets--; } }finally { lock.unlock(); } } }}
1.13 线程通讯
- 线程通信一定是多个线程在操作同一个资源才需要通信
方法名 | 说明 |
---|---|
public void wait() | 让当前线程进入到等待状态,此方法必须锁对象调用 |
public void notify() | 唤醒当前锁对象上等待状态的某个线程,此方法必须锁对象调用 |
public void notifyAll() | 唤醒当前锁对象上等待状态的全部线程,此方法必须锁对象调用 |
1.14 生产者消费者
1.14.1 生产者消费者概述
- 为了体现生产和消费过程中的等待和唤醒,Java就提供了几个方法供我们使用,这几个方法在Object类中
- Object类的等待和唤醒方法
方法名 | 说明 |
---|---|
void wait() | 导致当前线程等待,直到另一个线程调用该对象的 notify() 方法或 notifyAll() 方法 |
void notify() | 唤醒正在等待对象监视器的单个线程 |
void notifyAll() | 唤醒正在等待对象监视器的所有线程 |
1.14.2 生产者消费者案例
- 奶箱类
package test;//1:定义奶箱类public class Box { //定义一个成员变量,表示第x瓶奶 private int milk; //定义一个成员变量表示奶箱的状态 private boolean state = false; //提供存储牛奶和获取牛奶的操作 public synchronized void put(int milk) { //如果有牛奶等待消费 if(state) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果没有牛奶,就生产牛奶 this.milk = milk; System.out.println("送奶工将第" + this.milk + "瓶奶放入奶箱"); //生产完毕后,修改奶箱状态 state = true; //唤醒其他等待线程 notifyAll(); } public synchronized void get() { //如果没有牛奶,就等到生产 if(!state) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果有牛奶,就消费牛奶 System.out.println("用户拿到第" + this.milk + "瓶奶"); //消费完毕后,修改奶箱状态 state = false; //唤醒其他等待线程 notifyAll(); }}
- 生产者类
package test;//2:生产者类(Producer):实现Runnable接口public class Producer implements Runnable { private Box b; public Producer(Box b) { this.b = b; } //重写run()方法,调用存储牛奶的操作 @Override public void run() { for (int i = 1; i
- 消费者类
package test;//3:消费者类(Customer);实现Runnable接口public class Customer implements Runnable{ private Box b; public Customer(Box b) { this.b = b; } //重写run()方法,调用获取牛奶的操作 @Override public void run() { while(true) { b.get(); } }}
- 测试类
package test;public class BoxDemo { public static void main(String[] args) { //创建奶箱对象,这是共享数据区域 Box b = new Box(); //创建生产者对象,把奶箱对象作为构造方法参数传递。因为在这个类中要谓用存储牛奶的操作 Producer p = new Producer(b); //创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作 Customer c =new Customer(b); //创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递 Thread t1 = new Thread(p); Thread t2 = new Thread(c); //启动线程 t1.start(); t2.start();// 送奶工将第1瓶奶放入奶箱// 用户拿到第1瓶奶// 送奶工将第2瓶奶放入奶箱// 用户拿到第2瓶奶// 送奶工将第3瓶奶放入奶箱// 用户拿到第3瓶奶// 送奶工将第4瓶奶放入奶箱// 用户拿到第4瓶奶// 送奶工将第5瓶奶放入奶箱// 用户拿到第5瓶奶 }}
推荐学习:《java视频教程》
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!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Guide du nombre de Smith en Java. Nous discutons ici de la définition, comment vérifier le numéro Smith en Java ? exemple avec implémentation de code.

Dans cet article, nous avons conservé les questions d'entretien Java Spring les plus posées avec leurs réponses détaillées. Pour que vous puissiez réussir l'interview.

Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est

Guide de TimeStamp to Date en Java. Ici, nous discutons également de l'introduction et de la façon de convertir l'horodatage en date en Java avec des exemples.

Les capsules sont des figures géométriques tridimensionnelles, composées d'un cylindre et d'un hémisphère aux deux extrémités. Le volume de la capsule peut être calculé en ajoutant le volume du cylindre et le volume de l'hémisphère aux deux extrémités. Ce tutoriel discutera de la façon de calculer le volume d'une capsule donnée en Java en utilisant différentes méthodes. Formule de volume de capsule La formule du volume de la capsule est la suivante: Volume de capsule = volume cylindrique volume de deux hémisphères volume dans, R: Le rayon de l'hémisphère. H: La hauteur du cylindre (à l'exclusion de l'hémisphère). Exemple 1 entrer Rayon = 5 unités Hauteur = 10 unités Sortir Volume = 1570,8 unités cubes expliquer Calculer le volume à l'aide de la formule: Volume = π × r2 × h (4

PHP et Python ont chacun leurs propres avantages, et le choix doit être basé sur les exigences du projet. 1.Php convient au développement Web, avec une syntaxe simple et une efficacité d'exécution élevée. 2. Python convient à la science des données et à l'apprentissage automatique, avec une syntaxe concise et des bibliothèques riches.

PHP est un langage de script largement utilisé du côté du serveur, particulièrement adapté au développement Web. 1.Php peut intégrer HTML, traiter les demandes et réponses HTTP et prend en charge une variété de bases de données. 2.PHP est utilisé pour générer du contenu Web dynamique, des données de formulaire de traitement, des bases de données d'accès, etc., avec un support communautaire solide et des ressources open source. 3. PHP est une langue interprétée, et le processus d'exécution comprend l'analyse lexicale, l'analyse grammaticale, la compilation et l'exécution. 4.PHP peut être combiné avec MySQL pour les applications avancées telles que les systèmes d'enregistrement des utilisateurs. 5. Lors du débogage de PHP, vous pouvez utiliser des fonctions telles que error_reportting () et var_dump (). 6. Optimiser le code PHP pour utiliser les mécanismes de mise en cache, optimiser les requêtes de base de données et utiliser des fonctions intégrées. 7

Java est un langage de programmation populaire qui peut être appris aussi bien par les développeurs débutants que par les développeurs expérimentés. Ce didacticiel commence par les concepts de base et progresse vers des sujets avancés. Après avoir installé le kit de développement Java, vous pouvez vous entraîner à la programmation en créant un simple programme « Hello, World ! ». Une fois que vous avez compris le code, utilisez l'invite de commande pour compiler et exécuter le programme, et « Hello, World ! » s'affichera sur la console. L'apprentissage de Java commence votre parcours de programmation et, à mesure que votre maîtrise s'approfondit, vous pouvez créer des applications plus complexes.
