【java基础】多线程(超详细)

如有错写或表述不清楚的地方,欢迎各位大佬指摘
写这篇文档主要是因为博主准备跳槽了,面试不可缺少的八股文,自己也正在重新回顾,就把这些东西记录下来,希望对其他需要面经的人有帮助

1、进程与线程

刚开始学习线程的同学,可能会有人弄混这俩个名词

进程:可以看作我们经常打的游戏,王者荣耀是个进程,原神是个进程,这两个进程都是独立的,互不影响,王者输了对原神的抽卡没有任何影响

线程:线程又分为单线程与多线程,单线程就比如我们在跑图的时候不能同时去抽卡,只能按顺序去执行,多线程就比如地铁的闸机口,可以在第一个口进,也可以在第二进,不需要互相等待,所以多线程是可以提高我们程序的处理效率的

2、线程提交任务的流程

我们先了解一下线程提交任务的流程,有个大概了解后,我们在去讲解线程的生命周期与线程的实现方法

开始
提交Runnable
线程数 < 当前核心线程数
创建新线程 并把当前Runnable作为线程的第一个任务
将当前任务进行入队
判断队列是否以及满了
入队 等待执行
线程书<最大线程数
创建新线程 并把当前Runnable作为线程的第一个任务
拒绝任务

流程图如果大家看的不明白的话,给大家大白话描述一下(本博的表达能力真的很…),有兴趣的小伙伴也可也看下 execute() 方法中的代码处理逻辑
1.提交一个Runnable
2.判断当前的线程数是否小于当前核心线程数
3.如果小于,那就创建一个新线程并执行Runnable
4.如果大于等于,那就将这个线程放入队列中
5.如果队列没有满,那就将Runnable放入,等待执行
6.如果队列满了,入队失败会尝试继续追加线程
7.判断当前线程数是否小于最大线程数
8.如果小于,那就创建线程并执行任务
9.如果大于等于,那就拒绝执行此Runnable(其实就是抛异常了)

3、线程的生命周期

线程被创建并启动后,他不是一启动就进入了执行状态,也不是一直处于执行状态,在线程的生命周期中,他要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)五种状态,当线程启动后,他不会一直霸占着CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换

在这里插入图片描述

4、线程的实现方式

在java中线程的创建方式有两种,一个是继承java.lang.Thread类,一个是实现java.lang.Runnable接口

4.1、第一种方式继承Thread类

Thread其实本质上还是实现了Runnable接口的一个实例
启动线程的唯一方式是通过调用线程对象的start(),他将启动一个新线程,并执行run()方法

示例代码:

class MyThread extends Thread {
    public void run() {
        // 线程任务逻辑
    }
}

public class Main {
    public static void main(String[] args) {
        // 新建线程
        MyThread thread = new MyThread();
        // 不会启动线程,只是普通的调用方法,就是单线程
        // thread.run();
        // 启动线程
        thread.start();
    }
}

问题:start()与run()的区别
1.thread.start()方法是启动线程,在jvm中开辟了一个新的栈空间,真正实现了多线程运行,这时不需要等待run()方法执行完毕,就可以直接继续调用下面的方法,此时线程是处于就绪状态,并没有运行,线程启动成功后线程会自动调用run()方法

2.thread.run()方法称为线程体,包含了要执行的这个线程的内容,现在就进入了运行状态,开始运行run函数中的代码,run方法运行结束,此线程终止,然后CPU在调度其他线程

4.2、第二种方式实现Runnable接口

当自己的类以及继承另一个类就无法直接继承Thread ,此时可以实现一个Runnable接口,所以这种方式更灵活

class MyRunnable implements Runnable {
    public void run() {
        // 线程任务逻辑
    }
}

public class Main {
    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        // 创建线程
        Thread thread = new Thread(runnable);
        // 启动线程
        thread.start();
    }
}

使用匿名内部类创建:

public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            public void run() {
                // 线程任务逻辑
            }
        });
        // 启动线程
        thread.start();
    }
}

5、关于线程的结束方法(DEAD)

线程会以下面四种方式结束,结束后就是死亡状态

5.1、正常结束

显而易见就是线程正常结束,run()或call()方法执行完毕

5.2、异常

线程抛出一个未捕获的Exception

5.3、Stop方法终止(不推荐,了解就可)

直接调用线程的stop()方法来结束该线程 -------- 该方法通常容易导致死锁,不推荐!!!!!!!
此方法就像突然拔掉了电脑电源,可能会产生不可预料的结果

5.3、interrupt方法终止(常用)

public class MyThread extends Thread {
    public void run() {
        try {
            // 线程执行的代码
            // ...
            
            // 在执行过程中检查中断状态
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }
            
            // 继续执行剩余的代码
            
        } catch (InterruptedException e) {
            // 处理中断异常
        }
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
        
        // 中断线程
        thread.interrupt();
    }
}

由上述代码所示,interrupt方法来中断线程有两种情况

1.线程处于阻塞状态,比如使用了sleep(),当调用线程interrupt()方法时,会抛出InterruptedException 异常,通过代码捕获改异常后,然后可以使用break跳出循环状态,从而让我们有机会结束这个线程的执行,通常很多人认为只要调用interrupt()方法线程就会结束,其实是错的,一定要先捕获InterruptedException 异常后通过break跳出循环从而正常结束run方法

2.非阻塞状态,使用interrupted()来判断线程的终止标志来退出循环,当使用interrupt()时,中断标志就会置为true

未完…待续…

  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值