【JavaEE初阶】之 多线程基础【上篇】

✨✨hello,愿意点进来的小伙伴们,你们好呐!
🐻🐻系列专栏:【JavaEE】
🐲🐲本篇内容:带你从0到1了解多线程基槽
🐯🐯作者简介:一名现大二的三非编程小白,日复一日,仍需努力。

多线程有关概念

1. 程序
》》为了完成特定的任务,用某种语言编写的一组指令的集合,就是我们写的代码就称为程序。
2. 进程
进程就是指在运行中的程序,比如我们使用的某个软件,就启动了一个进程,操作系统就会在内存中给我们分配内存空间,然后又启动另一个软件的话,就又开启了一个进程,操作系统又会为这个进程分配内存空间。进程是程序的一次执行过程,在该过程中存在着产生,存在,消亡。
3.线程
线程就是由进程创建的,是进程的一个体现。一个进程可以同时开启多个线程。
线程可以分为单线程与多线程:
单线程:
在同一个时刻只允许执行一个线程。
多线程:
在同一个深刻,可以执行多个线程,就比如QQ ,可以在同一时刻打开多个聊天框。网易云音乐可以同时下载多曲音乐。
4.并发与并行:
并发:
在同一时刻,多个任务交替执行,一个CPU一直在多个任务之间切换运行,这种就叫做并发,给人一个貌似同时的错觉。单核CPU实现多任务的就是并发。
在这里插入图片描述
在这里插入图片描述
并发:
在同一时刻,多个任务同时执行。多个CPU执行不同的任务,多核CPU就可以实现并行。
在这里插入图片描述

线程基本使用:

了解了线程的相关概念后,我们来来看看一个线程究竟要怎么来创建吧。

创建线程的方式:

在Java中创建线程有两种方法:1.继承Thread类,2.实现Runnable接口。

1.继承Thread类:

我们要编写一个程序来开启一个线程,该线程每隔一秒在控制台输出 “小狗汪汪叫”,当执行到80次就结束该进程。

1.我们编写一个Dog类,该类要继承Thread类。
2. 然后我们在Dog类中要重写run方法。在该方法中编写要进程执行的语句
3.在main方法中创建Dog类的对象,然后调用start方法。
这时候就创建了一个进程·。

那这个时候我们就会有一个疑问了:我们是重写一个run方法,但是为什么创建线程调用的是start方法呢?这时候我们来看看源码中调用start会发生什么事情吧。

public class Test02 {
    public static void main(String[] args) {
        DOg dog = new DOg();
        dog.start();
    }
}

class DOg extends Thread {
    @Override
    public void run() {

        for (int i = 0; i < 80; i++) {
            System.out.println("小狗汪汪叫~~~~");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

1.
在这里插入图片描述

2.在start方法中调用start0方法
在这里插入图片描述

3.start0方法底层是由C/C++来编写的,但是调用该方法后,也不一定会执行,只是将线程变为可运行状态,最终运行是通过CPU调用的,取决于CPU。在该方法中再调用我们刚刚重写的run方法。

在这里插入图片描述

2.实现Runnable接口:

1. 我们需要在Dog类实现Runnable接口
2. 然后重写run方法,在该方法中编写要执行的代码。
3. 然后在main方法中我们要创建Dog的对象,然后创建Thread对象,将Dog对象传入。
4.最后也是调用start方法。

为什么创建Thread对象可以传入Dog对象呢?
在这里插入图片描述

因为在Threda的构造器中的形参可以传入一个Runnable类型的对象。这就是多态。

为什么调用的是start方法也和继承Thread的方式一样。

public class Test02 {
    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() {

        for (int i = 0; i < 80; i++) {
            System.out.println("小狗汪汪叫~~~~");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

多线程执行:

在这里插入图片描述

public class Test02 {
    public static void main(String[] args) {
         T3 t3 = new T3();
         T4 t4 = new T4();
        Thread thread1 = new Thread(t3);
        Thread thread2 = new Thread(t4);
        thread1.start();
        thread2.start();
    }
}
class T3 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("hello,world");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class T4 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("hi");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

我们来分析一下该程序的线程创建

先创建main主线程,然后在主线程中创建两个子线程。在在main线程销毁的时候子线程也不会销毁

在这里插入图片描述

继承Thread类 与实现 Runnable接口的区别

在创建线程本质上来说,继承Thread与实现Runnable接口来创建线程是没有什么区别的。
但是在Java单继承机制中,有时候我们要一个继承了别的类的类来创建进程就需要实现Runnable接口来实现。
实现Runnable接口更加适合多个线程共享一个资源的情况。

线程终止问题:

线程在哪种情况下会终止呢?
当线程完成任务后,会自动退出。
我们也可以通过控制变量来控制run方法退出。这种方法叫做通知方法,接下来我们来介绍要怎么实现通知方法

我们在run方法中使用while循环,并定义一个boolean变量来充当while循环的条件。
然后在main主线程中调用T3子线程,并让主线程休眠10秒钟,后改变T3中的loop变量,使while循环结束,即控制子线程结束。
这就是通知方法。

public class Test02 {
    public static void main(String[] args) throws InterruptedException {
         T3 t3 = new T3();
        Thread thread = new Thread(t3);
        thread.start();
        Thread.sleep(10000);
        t3.setLoop(false);
    }
}
class T3 implements Runnable{
    private boolean loop = true;

    public boolean getLoop() {
        return loop;
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }

    @Override
    public void run() {
        while(loop){
            System.out.println("hello,world");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

线程礼让与线程插队:

在这里插入图片描述

线程礼让:

public class Test02 {
    public static void main(String[] args) throws InterruptedException {
         T3 t3 = new T3();
        Thread thread = new Thread(t3);
        for (int i = 0; i < 20; i++) {
            Thread.sleep(1000);
            if (i == 10){
                Thread.yield();
            }
            System.out.println("main执行");
        }
    }
}
class T3 implements Runnable{
  

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("hello,world");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述
因为目前CPU资源充足,所以该线程礼让不成功。

线程插队:

public class Test02 {
    public static void main(String[] args) throws InterruptedException {
        T3 t3 = new T3();
        Thread thread = new Thread(t3);
        t3.start();
        for (int i = 0; i < 20; i++) {
            Thread.sleep(1000);
            if (i == 10){
                t3.join();
            }
            System.out.println("main执行");
        }
    }
}
class T3 extends Thread{


    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("hello,world");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述

这时候子线程插队插入主线程当中。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无满*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值