Maison  >  Article  >  Java  >  Résumé des points de connaissances Java : bases du multithreading

Résumé des points de connaissances Java : bases du multithreading

WBOY
WBOYavant
2022-11-15 17:24:221849parcourir

Cet article vous apporte des connaissances pertinentes sur java, qui présente principalement le contenu pertinent sur le multi-threading. Plusieurs threads peuvent être exécutés en même temps. Par exemple : vous pouvez utiliser Thunder pour télécharger plusieurs fichiers en même temps. Jetons-y un coup d'œil. J'espère que cela sera utile à tout le monde.

Résumé des points de connaissances Java : bases du multithreading

Apprentissage recommandé : "Tutoriel vidéo Java"

1. Concepts liés au fil

1 Programme : Il s'agit d'un ensemble d'instructions écrites dans un certain langage pour accomplir une tâche spécifique. Pour faire simple : est le code que nous écrivons. 就是我们写的代码

2、进程:是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为 该进程分配内存空间。当我们使用迅雷,又启动了一个进程,操作系统将为迅雷分配新的内存空间。

进程是程序的一次执行过程,或是正在运行的一个程序。是动态过程:有它自身的产生、存在和消亡的过程。

3、线程:是进程创建的,是进程的实体,一个进程可以有多个线程,例如使用迅雷下载文件,迅雷相当于进程,下载的文件相当于线程。

4、单线程:同一时刻,只允许执行一个线程

5、多线程:同一时刻,可以执行多个线程。例如:使用迅雷可以同时下载多个文件。

6、并发:同一时刻,多个任务交替进行。单核CPU实现的多任务就是并发。

7、并行:同一时刻,多个任务同时进行。多核CPU可以实现并行,当任务较多时,并发和并行有可能同时发生。

二、线程基本使用

创建线程有两种方法:

1、继承Thread类,重写run方法。

2、实现Runnable接口,重写run方法。

注意:Thread类实现了Runnable接口。

(一) 继承Thread类,重写run方法

public class Thread01 {
    public static void main(String[] args) throws InterruptedException {
        Cat cat = new Cat();
        cat.start();
        System.out.println("主线程" + Thread.currentThread().getName());
        for (int i = 1; i <p>1、在继承<code>Thread</code>类,重写了<code>run()</code>方法后,在<code>main</code>方法中需要创建对象,并调用<code>start()</code>方法,启动线程。</p><p>2、使用<code>start()</code>方法,会调用重写的<code>run()</code>方法。</p><p>3、如果<code>main</code>方法中,<code>start()</code>方法后面还有执行语句,并且<code>run()</code>方法中也有执行语句,<code>main</code>线程中会启动一个子线程<code>Thread-0</code>,主线程不会阻塞,主线程与子线程会交替执行。</p><p>注意:如果主线程执行完毕,但子线程未执行完,进程不会结束,所有线程执行完毕后,进程自动结束。</p><p>4、在主线程中为什么使用<code>start()</code>方法去调用<code>run()</code>方法,而不是直接调用<code>run()</code>方法,因为<code>run()</code>方法是一个普通方法,没有真正启动线程,如果调用<code>run()</code>方法,就会将<code>run()</code>方法执行完毕后,再执行<code>main</code>方法剩余语句,主线程就会阻塞。</p><p>所以上面程序都运算结果是:</p><pre class="brush:php;toolbar:false">主线程main
主线程i=1你好1Thread-0主线程i=2你好2Thread-0主线程i=3你好3Thread-0主线程i=4你好4Thread-0主线程i=5你好5Thread-0

(二) 实现Runnable接口,重写run方法

public class Thread02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Thread thread = new Thread(dog);
        thread.start();
    }}class Dog implements Runnable{
    @Override    public void run() {
        int count = 0;
        while (true) {
            System.out.println("小狗汪汪叫" + (++count) + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 10){
                break;
            }
        }
    }}

1、因为Runnable接口中没有start()方法,所以需要代理

2、先在main方法中需要创建对象,然后创建一个Thread对象,将之前创建的对象传入Thread,借助Thread,调用start()方法,创建线程。

3、建议使用Runnable,因为实现Runnable接口更加适合多个线程共享一个资源的情况,避免了单继承的限制。

三、线程终止

(一)基本说明

1、当线程执行完任务时会自动退出。

2、也可以使用变量控制run()方法退出终止线程。

(二)操作

1、如果一个线程中的run()方法内部是一个while(true){},即一个无限循环

2、我们可以在线程内部,创建一个boolean属性loop,让loop = true,然后while(loop){}

3、再提供一个setLoop

2.

Processus : fait référence à un programme en cours d'exécution. Par exemple, lorsque nous utilisons QQ, nous démarrons un processus et le système d'exploitation allouera de l'espace mémoire pour le processus. Lorsque nous utilisons Thunder et démarrons un autre processus, le système d'exploitation allouera un nouvel espace mémoire pour Thunder.

Un processus est une exécution d'un programme, ou un programme en cours d'exécution. Il s’agit d’un processus dynamique : il a son propre processus d’émergence, d’existence et de disparition.

3. Thread

 : Il est créé par le processus et est l'entité du processus. Un processus peut avoir plusieurs threads. Par exemple, en utilisant Thunder pour télécharger des fichiers, Thunder est équivalent au. processus, et le fichier téléchargé est équivalent au fil .

4. Un seul thread

 : En même temps, un seul thread est autorisé à s'exécuter.

5. Multi-threading

 : En même temps, peut exécuter plusieurs threads. Par exemple : en utilisant Thunder, vous pouvez télécharger plusieurs fichiers en même temps. 🎜🎜6. 🎜Concurrency🎜 : En même temps, plusieurs tâches sont effectuées en alternance. Le multitâche réalisé par un processeur monocœur est la concurrence. 🎜🎜7, 🎜Parallèle🎜 : En même temps, plusieurs tâches sont effectuées simultanément. Les processeurs multicœurs peuvent réaliser le parallélisme. Lorsqu'il existe de nombreuses tâches, la concurrence et le parallélisme peuvent se produire en même temps. 🎜🎜🎜2. Utilisation de base des threads 🎜🎜Il existe deux façons de créer un thread : 🎜🎜1 Hériter de la classe Thread et remplacer run<.> méthode. 🎜🎜2. Implémentez l'interface <code>Runnable et remplacez la méthode run. 🎜🎜Remarque : La classe Thread implémente l'interface Runnable. 🎜🎜🎜(1) Héritez de la classe Thread et remplacez la méthode d'exécution🎜
public class ThreadExit {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.start();
        Thread.sleep(10000);
        t.setLoop(false);
    }}class T extends Thread{
    private boolean loop = true;
    private int times = 0;
    
    @Override    public void run() {
        while (loop){
            System.out.println("hello" + (++times));
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }}
🎜1 Héritez de la classe Thread et réécrivez le run()
Après la méthode code>, vous devez créer un objet dans la méthode main et appeler la méthode start() pour démarrer le thread. 🎜🎜2. L'utilisation de la méthode start() appellera la méthode run() remplacée. 🎜🎜3. Si dans la méthode main, il y a des instructions d'exécution après la méthode start(), et il y a aussi des instructions d'exécution dans run(), un sous-thread <code>Thread-0 sera démarré dans le thread main. Le thread principal ne bloquera pas, ainsi que le thread principal et le sous-thread. s'exécutera en alternance. 🎜🎜Remarque : si le thread principal termine l'exécution, mais que le thread enfant n'a pas terminé son exécution, le processus ne se terminera pas une fois l'exécution de tous les threads terminée, le processus se terminera automatiquement. 🎜🎜4. Pourquoi utiliser la méthode start() pour appeler la méthode run() dans le thread principal au lieu d'appeler directement la méthode run() méthode ? , car la méthode run() est une méthode ordinaire et ne démarre pas réellement le thread. Si la méthode run() est appelée, la méthode run. () Une fois la méthode exécutée, si les instructions restantes de la méthode main sont exécutées, le thread principal sera bloqué. 🎜🎜Le résultat du programme ci-dessus est donc : 🎜
public class ThreadMethod01 {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.setName("邱崇源");
        t.setPriority(1);
        t.start();
        for (int i = 0; i 🎜<a id="_Runnablerun_66">🎜(2) Implémentez l'interface Runnable et réécrivez la méthode d'exécution🎜<pre class="brush:php;toolbar:false">public class ThreadMethod02 {
    public static void main(String[] args) throws InterruptedException {
        A a = new A();
        a.start();
        for (int i = 1; i 🎜1 Parce qu'il n'y a rien de tel dans le <code. m>start()</code.>
de l'interface >Runnable, donc agent est requis. 🎜🎜2. Tout d'abord, créez un objet dans la méthode principale, puis créez un objet Thread, transmettez l'objet précédemment créé dans Thread et utilisez Thread pour appeler . méthode start () pour créer un fil de discussion. 🎜🎜3. Il est recommandé d'utiliser Runnable, car l'implémentation de l'interface Runnable est plus adaptée au partage d'une ressource par plusieurs threads et évite les limitations de l'héritage unique. 🎜🎜🎜3. Fin du fil 🎜🎜🎜(1) Instructions de base🎜🎜1. Lorsque le fil termine la tâche, il se ferme automatiquement. 🎜🎜2. Vous pouvez également utiliser des variables pour contrôler la méthode run() afin de quitter le thread terminé. 🎜🎜🎜(2) Opération🎜🎜1. Si la méthode run() dans un fil est en interne un while(true){}, c'est-à-dire une boucle infinie. 🎜🎜2. Nous pouvons créer une boucle d'attribut booléen à l'intérieur du fil, laisser loop = true, puis while(loop){}. 🎜🎜3. Fournissez une autre méthode setLoop, afin que vous puissiez appeler la méthode setLoop dans d'autres classes et modifier la valeur booléenne pour contrôler la fin du thread. 🎜🎜🎜🎜 (3) Démonstration de code 🎜
public class ThreadMethod03 {
    public static void main(String[] args) throws InterruptedException {
        MyDaemonThread myDaemonThread = new MyDaemonThread();
        myDaemonThread.setDaemon(true);
        myDaemonThread.start();
        for (int i = 1; i 🎜🎜🎜 4. Méthodes de thread courantes 🎜🎜🎜🎜 (1) Le premier groupe 🎜🎜1, 🎜setName🎜 : Définissez le nom du fil pour qu'il soit identique au nom du paramètre. 🎜<p>2、<strong>getName</strong>:返回该线程名称。</p><p>3、<strong>start</strong>:使该线程开始执行,JAVA虚拟机底层调用该线程的start0方法。</p><p>4、<strong>run</strong>:调用线程对象的run方法。</p><p>5、<strong>setPriority</strong>:更改线程的优先级。</p><p>6、<strong>getPriority</strong>:获取线程的优先级。</p><p>7、<strong>sleep</strong>:在指定的毫秒数内,让当前正在执行的线程休眠。</p><p>8、<strong>interrupt</strong>:中断线程。</p><h4>
<a id="_147"></a>注意事项:</h4><p>1、<code>start()</code>底层会创建新的线程,调用run(),<code>run()</code>就是一个简单的方法调用,<code>不会启动新线程</code>。</p><p>2、<code>中断线程一般用于中断正在休眠的线程</code>,并没有真正的结束线程,所以如果线程中每输出内容后,会调用<code>Thread.sleep()</code>进行休眠的话,我们可以调用<code>interrupt()</code>方法将其<code>提前唤醒</code>。</p><h4>
<a id="_150"></a>代码演示:</h4><pre class="brush:php;toolbar:false">public class ThreadMethod01 {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.setName("邱崇源");
        t.setPriority(1);
        t.start();
        for (int i = 0; i <h4>
<a id="_183"></a>(二)第二组</h4><p>1、<strong>yield</strong>:是一个<code>静态方法</code>,表示<code>线程的礼让</code>。让出<code>CPU</code>,让其他线程执行,但是<code>不一定成功</code>,因为这取决于CPU,如果CPU认为两个线程可以一起执行,则不进行礼让,所以<code>如果CPU的核数多,并且线程数少,礼让就会大概率失败</code>。</p><p>2、<strong>join</strong>:表示<code>线程的插队</code>,假如主线程与子线程正在交替运行,我们想<code>先让子线程执行</code>完毕,然后再让主线程执行,就可以使用线程插队,在主线程中,创建子线程对象,并调用<code>join</code>方法,可以实现线程插队,线程插队<code>一定会成功</code>,先<code>执行完插入线程任务后,再继续执行主线程</code>。</p><h4>
<a id="_186"></a>代码演示:</h4><pre class="brush:php;toolbar:false">public class ThreadMethod02 {
    public static void main(String[] args) throws InterruptedException {
        A a = new A();
        a.start();
        for (int i = 1; i <h2>
<a id="_219"></a>五、用户线程和守护线程</h2><p>1、<strong>用户线程</strong>:也叫<code>工作线程</code>,线程的任务执行完或通知方式结束。</p><p>2、<strong>守护线程</strong>:一般是<code>为工作线程服务</code>的,当<code>所有的用户线程结束</code>,<code>守护线程自动结束</code>。</p><h4>
<a id="_222"></a>应用场景:</h4><p>如果有两个线程,主线程运行结束,但子线程是无限循环。我们想让主线程结束的同时,子线程也结束,就需要让子线程变成守护线程。</p><p>在主线程中,创建子线程对象,并调用<code>setDaemon(true)</code>,让子线程变成守护线程。</p><p>注意:一定要放在<code>start方法之前</code>。</p><h4>
<a id="_226"></a>代码演示:</h4><pre class="brush:php;toolbar:false">public class ThreadMethod03 {
    public static void main(String[] args) throws InterruptedException {
        MyDaemonThread myDaemonThread = new MyDaemonThread();
        myDaemonThread.setDaemon(true);
        myDaemonThread.start();
        for (int i = 1; i <h2>
<a id="_254"></a>六、线程的生命周期</h2><h4>
<a id="1JDK__ThreadState__255"></a>1、JDK 中用 Thread.State 枚举表示了线程的几种状态</h4><p><img src="https://img.php.cn/upload/article/000/000/067/2235493b090cc60a6a3c1434c8852f59-0.png" alt="Résumé des points de connaissances Java : bases du multithreading"></p><h4>
<a id="2_257"></a>2、线程状态转换图</h4><p><img src="https://img.php.cn/upload/article/000/000/067/cfbba58b413c41b084c9e0cab6295dfe-1.png" alt="Résumé des points de connaissances Java : bases du multithreading"></p><h2>
<a id="_259"></a>七、线程的同步</h2><h4>
<a id="1_260"></a>1、应用场景:</h4><p>假如有100张票,有三个线程同时进入该方法买票,票就有可能超卖。所以我们需要线程同步机制,保证数据在同一时刻,最多有一个线程访问。</p><p>可以采取同步方法,在方法中加入<code>synchronized</code>关键字。</p><p>也可以采用同步代码块,<code>synchronized(对象){}</code>。</p><p>注意:<code>synchronized是非公平锁</code>,如果这次第一个线程访问了数据,那么下一次第一个线程也有可能访问到数据。</p><p>如果同步方法是<code>非静态</code>的,那么锁可以是this,也可以是其他对象,但要求是同一个对象。</p><p>例:<code>synchronized(this)</code>。</p><p>如果同步方法是<code>静态</code>的,锁为当前类本身。</p><p>例:<code>synchronized(类名:class)</code>。</p><h4>
<a id="2_270"></a>2、代码演示:</h4><pre class="brush:php;toolbar:false">public class SellTicket {
    public static void main(String[] args) {
        SellTicket02 sellTicket04 = new SellTicket02();
        Thread thread1 = new Thread(sellTicket04);
        Thread thread2 = new Thread(sellTicket04);
        Thread thread3 = new Thread(sellTicket04);
        thread1.start();
        thread2.start();
        thread3.start();
    }}class SellTicket02 implements Runnable {
    public static int ticket = 100;
    private boolean loop = true;

    public synchronized void sell() {
        if (ticket <h2>
<a id="_309"></a>八、线程的死锁</h2><h4>
<a id="1_310"></a>1、基本介绍</h4><p>多个线程都占用了对方的锁资源,但不肯相让,就导致了死锁,在编程中,一定要避免死锁的发生。</p><h4>
<a id="2_312"></a>2、发生场景:</h4><p>例如:A和B的面前都各有两道门,A的第一道门是o1,第二道门是o2。B的第一道门是o2,第二道门是o1。他们的面前有两把锁,一个是o1锁,一个是o2锁,假如A抢到了o1锁,B抢到了o2锁,但是他们只可打开各自的第一道门,第二道门都没有打开,那么他们都无法释放自己的锁资源,又不可能相让,因此发生了死锁。</p><h4>
<a id="3_314"></a>3、代码演示:</h4><pre class="brush:php;toolbar:false">public class DeadLock_ {
	public static void main(String[] args) { //模拟死锁现象 
		DeadLockDemo A = new DeadLockDemo(true); 
		A.setName("A 线程"); 
		DeadLockDemo B = new DeadLockDemo(false); 
		B.setName("B 线程");
		A.start(); 
		B.start(); 
	} }class DeadLockDemo extends Thread { 
	static Object o1 = new Object();// 保证多线程,共享一个对象,这里使用 static 
	static Object o2 = new Object(); 
	boolean flag; 
	
	public DeadLockDemo(boolean flag) {//构造器 
		this.flag = flag; 
	}
	
	@Override 
	public void run() {  
		if (flag) { 
			synchronized (o1) { 
				System.out.println(Thread.currentThread().getName() + " 进入 1"); 
				synchronized (o2) { 
					System.out.println(Thread.currentThread().getName() + " 进入 2"); 
				} 
			} 
		} else {
			synchronized (o2) { 
				System.out.println(Thread.currentThread().getName() + " 进入 3"); 
				synchronized (o1) {  
					System.out.println(Thread.currentThread().getName() + " 进入 4"); 
				} 
			} 
		} 
	} }

九、释放锁

1、下面操作会释放锁

当前线程的同步方法,同步代码块执行结束。
当前线程在同步代码块,同步方法中遇到break,return
当前线程在同步代码块,同步方法中出现了未处理的错误或异常,导致异常结束。
当前线程在同步代码块,同步方法中执行的线程对象的wait方法,当前线程暂停,并释放锁。

2、 下面操作不会释放锁

线程执行同步代码块和同步方法时,程序调用Thread.sleep(),Thread.yield()方法暂停当前线程的执行,不会释放锁。
线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁。

推荐学习:《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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer