>  기사  >  Java  >  Java 지식 요약: 멀티스레딩 기초

Java 지식 요약: 멀티스레딩 기초

WBOY
WBOY앞으로
2022-11-15 17:24:221822검색

이 글에서는 동시에 여러 스레드를 실행할 수 있는 관련 내용을 주로 소개하는 java에 대한 관련 지식을 제공합니다. 예: Thunder를 사용하여 동시에 여러 파일을 다운로드할 수 있습니다. 모두에게 도움이 되기를 바랍니다.

Java 지식 요약: 멀티스레딩 기초

추천 학습: "java 비디오 튜토리얼"

1. 스레드 관련 개념

1. 프로그램: 특정 작업을 완료하기 위해 특정 언어로 작성된 지침 세트입니다. 간단히 말하면: 는 우리가 작성하는 코드입니다. 就是我们写的代码

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.

Process: 실행 중인 프로그램을 말합니다. 예를 들어 QQ를 사용하면 프로세스가 시작되고 운영 체제는 해당 프로세스에 메모리 공간을 할당합니다. Thunder를 사용하고 다른 프로세스를 시작하면 운영 체제는 Thunder에 새로운 메모리 공간을 할당합니다.

프로세스는 프로그램의 실행, 또는 실행 중인 프로그램입니다. 그것은 역동적인 과정입니다. 그것은 출현, 존재, 소멸이라는 고유한 과정을 가지고 있습니다.

3. Thread

: 프로세스에 의해 생성되며 프로세스의 엔터티입니다. 한 프로세스에 여러 스레드가 있을 수 있습니다. 예를 들어 Thunder는 파일을 다운로드하는 것과 같습니다. 프로세스이며 다운로드된 파일은 스레드와 동일합니다.

4. 단일 스레드

: 동시에 하나의 스레드만 실행하도록 허용합니다.

5. 멀티스레딩

: 동시에 여러 스레드를 실행할 수 있습니다. 예를 들어 Thunder를 사용하면 동시에 여러 파일을 다운로드할 수 있습니다. 🎜🎜6. 🎜동시성🎜: 동시에 여러 작업이 교대로 수행됩니다. 단일 코어 CPU로 달성되는 멀티태스킹은 동시성입니다. 🎜🎜7, 🎜Parallel🎜: 동시에 여러 작업이 동시에 수행됩니다. 멀티 코어 CPU는 작업이 많을 때 동시성과 병렬성이 동시에 발생할 수 있습니다. 🎜🎜🎜2. 스레드의 기본 사용 🎜🎜스레드를 만드는 방법에는 두 가지가 있습니다. 🎜🎜1 Thread 클래스를 상속하고 run 메소드. 🎜🎜2. <code>Runnable 인터페이스를 구현하고 run 메서드를 재정의합니다. 🎜🎜참고: Thread 클래스는 Runnable 인터페이스를 구현합니다. 🎜🎜🎜(1) Thread 클래스를 상속하고 실행 메서드를 재정의합니다.🎜
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 Thread 클래스를 상속하고 run()을 다시 작성합니다. code> 메서드 다음에는 <code>main 메서드에서 객체를 생성하고 start() 메서드를 호출하여 스레드를 시작해야 합니다. 🎜🎜2. start() 메서드를 사용하면 재정의된 run() 메서드가 호출됩니다. 🎜🎜3. main 메서드의 경우 start() 메서드 뒤에 실행문이 있고, run() 메서드, 하위 스레드 <code>Thread-0main 스레드에서 시작됩니다. 기본 스레드는 차단되지 않으며 기본 스레드와 하위 스레드는 차단되지 않습니다. 교대로 실행됩니다. 🎜🎜참고: 메인 스레드가 실행을 완료했지만 하위 스레드가 실행을 완료하지 않은 경우 모든 스레드가 실행을 완료한 후에도 프로세스가 자동으로 종료됩니다. 🎜🎜4. run()를 직접 호출하는 대신 start() 메서드를 사용하여 메인 스레드에서 run() 메서드를 호출하는 이유 > 메소드? run() 메소드는 일반 메소드이고 실제로 스레드를 시작하지 않기 때문입니다. run() 메소드가 호출되면 run이 실행됩니다. () 메소드가 실행된 후 main 메소드의 나머지 명령문이 실행되면 메인 스레드가 차단됩니다. 🎜🎜위 프로그램의 결과는 다음과 같습니다. 🎜
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) Runnable 인터페이스를 구현하고 실행 메서드를 다시 작성합니다🎜<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. 왜냐하면 실행 가능
인터페이스 start() 메서드이므로 에이전트가 필요합니다. 🎜🎜2 먼저 기본 메소드에서 객체를 생성한 다음 Thread 객체를 생성하고, 이전에 생성된 객체 를 Thread에 전달하고 Thread를 사용하여 를 호출합니다. start() 메소드를 사용하여 스레드를 생성합니다. 🎜🎜3. Runnable 인터페이스를 구현하는 것이 여러 스레드가 리소스를 공유하는 데 더 적합하고 단일 상속의 제한을 피하므로 Runnable을 사용하는 것이 좋습니다. 🎜🎜🎜3. 스레드 종료 🎜🎜🎜(1) 기본 지침🎜🎜1. 스레드가 작업을 완료하면 자동으로 종료됩니다. 🎜🎜2. 변수를 사용하여 run() 메서드를 제어하여 종료된 스레드를 종료할 수도 있습니다. 🎜🎜🎜(2) 작업🎜🎜1. 스레드의 run() 메서드가 내부적으로 while(true){}인 경우 >, 즉 무한 루프입니다. 🎜🎜2. 스레드 내부에 부울 속성 루프를 생성하고 loop = true로 설정한 다음 while(loop){}로 설정합니다. 🎜🎜3. 다른 클래스에서 setLoop 메서드를 호출하고 부울 값을 변경하여 스레드 종료를 제어할 수 있도록 또 다른 setLoop 메서드를 제공합니다. 🎜🎜🎜🎜 (3) 코드 데모 🎜
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. 일반적인 스레드 방법 🎜🎜🎜🎜 (1) 첫 번째 그룹 🎜🎜1, 🎜setName🎜: 스레드 이름을 매개변수 이름과 동일하게 설정합니다. 🎜<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="Java 지식 요약: 멀티스레딩 기초"></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="Java 지식 요약: 멀티스레딩 기초"></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视频教程

위 내용은 Java 지식 요약: 멀티스레딩 기초의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제