JavaEE——多线程Thread 类及常见方法

news/2024/9/28 1:21:04 标签: jvm, java, 开发语言

目录

 

一、Thread(String name)

二、是否后台线程 isDeamon()

三、是否存活 isAlive()

四、run()方法和start()方法的区别

五、中断线程

法一:

法二:

六、线程等待join()

七、线程休眠sleep()

一、Thread(String name)

定义:这个东西是给线程(thread 对象) 起一个名字。起一个啥样的名字,不影响线程本身的执行,仅仅只是影响到程序猿调试可以借助一些工具看到每个线程以及名字.很容易在调试中对线程做出区分。

那么如何查看线程的名字呢?这里jdk本身就自带了一个程序叫做jconsole可以用来查看本地进程。

那么首先先在我们自己idea里面创建一个线程demo8,右键运行,代码如下:

java">public class demo8 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (true){
                System.out.println("hello 1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"T1");
        t1.start();
 
        Thread t2 = new Thread(() -> {
            while (true){
                System.out.println("hello 2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"T2");
        t2.start();
    }
}

二、是否后台线程 isDeamon()

什么是后台线程呢?

如果线程是后台线程,就不影响 进程退出如果线程不是后台线程(前台线程),就会影响到进程退出。
创建的 t1 和 t2 默认都是前台的线程。
即使 main 方法执行完毕,进程也不能退出.得等 t1 和 t2 都执行完,整个进程才能退出!!!如果 t1 和 t2 是后台线程此时如果 main 执行完毕,整个进程就直接退出,t1 和 t2 就被强行终止了。

三、是否存活 isAlive()

这个属性的意思就是——操作系统中对应的线程是否正在运行
Thread t 对象的生命周期和内核中对应的线程,生命周期并不完全一致~~创建出 t 对象之后,在调用 start 之前,系统中是没有对应线程的~~在 run 方法执行完了之后, 系统中的线程就销毁了但是 t 这个对象可能还存在。通过 isAlive 就能判定当前系统的线程的运行情况。

如果 调用 start 之后, run 执行完之前,isAlive 就是返回 true

如果 调用 start 之前, run 执行完之后, isAlive 就返回 false

四、run()方法和start()方法的区别

1. start() 方法来启动线程,真正实现了多线程运行。这时无需等待 run 方法体代码执行完毕, 可以直接继续执行下面的代码。
2. 通过调用 Thread 类的 start()方法来启动一个线程, 这时此线程是处于 就绪状态 , 并没有运 行。
3. 方法 run()称为线程体,它包含了要执行的这个线程的内容,线程就进入了 运行状态,开始运 行 run 函数当中的代码 。 Run 方法运行结束, 此线程终止。然后 CPU 再调度其它线程。

run 单纯的只是一个普通的方法, 描述了任务的内容。

start 则是一个特殊的方法, 内部会在系统中创建线程。

看一段代码:

run() 方法只是一个普通的方法你在 main 线程里调用 run,其实并没有创建新的线程这个循环仍然是在 main 线程中执行。

之前我们已经看到了如何通过覆写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程 就开始运行了。
覆写 run 方法是提供给线程要做的事情的指令清单
线程对象可以认为是把 李四、王五叫过来了
而调用 start() 方法,就是喊一声: 行动起来! ,线程才真正独立去执行了。
调用 start 方法 , 才真的在操作系统的底层创建出一个线程 .

五、中断线程

中断线程的意思就是让一个线程停下来!

线程停下来的关键,是要让线程对应的 run 方法执行完(还有一个特殊的,是 main 这个线程对于 main 来说,得是 main 方法执行完,线程就完了)。

法一:通过共享的标记来进行沟通

手动设置一个标志位。
看一段代码:我们在这个代码里面创建一个标志位isquit,通过while(!isquit)来判断循环是否结束,可以通过手动的设置isquit的值来控制线程的结束与否。为什么在其他线程中修改isquit的值可以影响到当前线程呢?此处因为,多个线程共用同一个虚拟地址空间!!因此, main 线程修改的 isquit 和 t 线程判定的 isquit, 是同一个值。

java">public class demo10 {
    public static  boolean isquit = false;
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while(!isquit){
                System.out.println("hello Thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        //只要把这个isquit设置为true,进一步的run就执行完了,再进一步就是线程执行结束了。
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        isquit = true;
        System.out.println("终止线程!");
    }
}

那么像刚才那种写法并不够严谨,我们可以参考第二种写法。

.

法二: 调用 interrupt() 方法来通知

使用Thread中内置的标志位来判定。
我们可以通过:
Thread.interrupted()—— 一个静态的方法。
Thread.currentThread0.islnterrupted()—— 实例方法.

其中 currentThread 能够获取到当前线程的实例。

看新的代码段:

java">public class demo11 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()){
                System.out.println("hello thread!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //当触发异常之后 立刻退出循环
                    break;
                }
            }
        });
        t.start();
 
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 
        t.interrupt();
    }
}

那么使用这种方法的原因就是——这个代码绝大部分情况,都是在休眠状态阻塞,此处的中断,是希望能够立即产生效果。如果线程已经是阻塞状态下,此时设置标志位就不能起到及时唤醒的效果

异常处理方式:调用这个 interrupt 方法, 就会让 sleep 触发一个异常从而导致 线程从阻塞状态被唤醒。

+

 当下的代码,一旦触发了异常之后, 就进入了 catch 语句.在catch中,就单纯的只是打了一个日志
printStackTrace 是打印当前出现异常位置的代码调用栈,打完日志之后,就直接继续运行。

我们可以发现在代码的最后我们调用了interrupt()方法,那么调用这个方法可能产生两种情况。

1、如果t线程处在就绪状态,就是设置线程的标志位为true

2、如果t线程处在阻塞状态,就会触发一个InterruptException。

Thread.currentThread0.islnterrupted()—— 实例方法.

这个方法判定的标志位是 Thread 的普通成员,每个示例都有自己的标志位,所以一般无脑使用这个方法即可。

六、线程等待join()

在我们的日常开发中,因为线程之间的调度顺序是按照调度器来安排的,这个过程是随机,无序的,我们希望能够控制多个线程之间的调度顺序,那么线程等待就是一种方式。

要想实现线程等待这里会使用到一个函数叫做join(),即哪个线程调用join哪个线程就会进入阻塞状态。

代码演示:

java">public class demo12 {
    public static void main(String[] args) {
        Thread t = new Thread(() ->{
            for (int i = 0; i < 5; i++) {
                System.out.println("hello thread!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
 
        //在主线程中就可以使用一个等待操作,来等待t线程执行结束。
        try {
            t.join(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

我们可以看到在代码的后面出现了这么一行代码  t.join(10000);这里的意思就是让main线程等待t线程的run方法执行完毕,等待时间是10000ms。

七、线程休眠sleep()

这个线程休眠这里就不在过多赘述了,因为之前的案例中已经出现了很多的实例调用了sleep()方法。这里介绍一下进程中各个线程之间的关系。

进程是由PCB + 双向链表组成。这个说法是针对只有一个线程的进程,是如此的。
如果是一个进程有多个线程, 此时每个线程都有一个 PCB一个进程对应的就是一组 PCB 了。PCB 上有一个字段 tgroupld,这个 id 其实就相当于进程的 id.同一个进程中的若干个线程的 tgroupld 是相同的。

即某个线程调用了sleep()方法,PCB就会进入阻塞队列,操作系统调度线程的时候,就只是从就绪队列中挑选合适的 PCB到 CPU 上运行。阻塞队列里的 PCB 就只能干等着。


http://www.niftyadmin.cn/n/5680018.html

相关文章

初识Vue3(详细版)

目录 前言 Vue3简介 spring 和Vue3 区别 创建Vue3工程 1 使用vite 构建 0 前提;安装好node.js(node.js作为JavaScript的运行环境&#xff09; 1 打开终端&#xff0c;切换到桌面&#xff08;或自己专门创建一个文件夹单独放置&#xff09; 2 输入命令&#xff1a;npm ge…

怎样用云手机进行TikTok矩阵运营?

在运营TikTok矩阵时&#xff0c;许多用户常常面临操作复杂、设备过多等问题。如果你也感到操作繁琐&#xff0c;不妨考虑使用云手机。云手机具备丰富的功能&#xff0c;能够帮助电商卖家快速打造高效的TikTok矩阵。接下来&#xff0c;我们将详细解析这些功能如何提升你的运营效…

【4.6】图搜索算法-DFS和BFS解合并二叉树

一、题目 给定两个二叉树&#xff0c;想象当你将它们中的一个覆盖到另一个上时&#xff0c;两个二叉树的一些节点便会重叠。你需要将他们合并为一个新的二叉树。合并的规则是 如果两个节点重叠&#xff0c;那么将他们的 值相加作为节点合并后的新值&#xff0c;否则不为 NUL L…

浅谈抗量子密码学:保护未来的数字安全

一、引言 随着量子计算机技术的发展&#xff0c;传统的加密算法面临前所未有的挑战。量子计算机利用量子位&#xff08;qubits&#xff09;的特性&#xff0c;能够在理论上比经典计算机更快地破解现有的加密系统。为了应对这一威胁&#xff0c;研究者们正在开发所谓的“抗量子…

Docker全家桶:Docker Compose项目部署

在学习完了前面的基础知识之后&#xff0c;我们现在可以开始部署完整的项目了。项目分成两个部分&#xff0c;前端和后端&#xff0c;并且采用前后端分离的形式。对应到docker&#xff0c;就是前端和后端分别对应一个容器。把这两个容器加入到同一个网段中&#xff0c;就能够进…

栈的各种接口的实现(C)

栈的概念 栈&#xff1a; 一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。压栈&#xff1a;…

RuoYi若依框架学习:多环境配置

在开发过程中&#xff0c;项目往往需要在不同的环境&#xff08;如开发、测试和生产&#xff09;中运行。RuoYi框架支持通过配置文件轻松实现多环境管理。以下是如何配置和使用多环境的技术分析。 1. 环境配置文件 RuoYi框架使用application-{profile}.yml文件来管理不同环境…

双十一购物节:五大必买爆款科技好物,让你省钱又省心

双十一购物节&#xff0c;作为中国最大的在线购物狂欢节&#xff0c;每年都吸引着无数消费者的眼球。在这个购物盛宴中&#xff0c;科技产品因其创新性、实用性和高性价比而成为消费者关注的焦点。随着科技的飞速发展&#xff0c;越来越多的智能设备走进了我们的生活&#xff0…