JavaEE--Thread 类的基本用法(不看你会后悔的嘿嘿)

Thread类是JVM用来管理线程的一个类,换句话说,每个线程都唯一对应着一个Thread对象.

因此,认识和掌握Thread类弥足重要.

本文将从

  1. 线程创建
  2. 线程中断
  3. 线程等待
  4. 线程休眠
  5. 获取线程实例

等方面来进行具体说明.

1)线程创建

方法1:通过创建Thread类的子类并重写run () 方法

class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("thread");
    }
}
public class Thread1 {
    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.start();
        System.out.println("main");
    }
}

方法2:通过创建Runnable接口的实现类并重写run ()方法,传实现类的对象作为构造器

class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("thread");
    }
}
public class Thread2 {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyThread());
        thread.start();
        System.out.println("main");
    }
}

方法3:使用匿名类,new类,也就是创建该类的子类

public class Thread3 {
    public static void main(String[] args) {
        Thread thread = new Thread(){
            @Override
            public void run() {
                System.out.println("thread");
            }
        };
        thread.start();
        System.out.println("main");
    }
}

方法4:使用匿名内部类,new接口,也就是创建该接口的实现类

public class Thread4 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread");
            }
        });
        thread.start();
        System.out.println("main");
    }
}

方法5:使用lambda表达式(日常开发中使用最多的形式)

public class Thread5 {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            System.out.println("thread");
        });
        thread.start();
        System.out.println("main");

    }
}

2)线程中断

顾名思义,也就是让线程停止.

本质上而言,让线程停止,方法就一种 -->执行完线程入口方法(run ()方法).

只不过此处可能是正常执行结束,也可能是因为异常而导致结束.

目前常见的有以下两种方式:
1.使用自定义的变量来作为标志位
2.使用Thread提供的变量来作为标志位

下面来介绍:

方法1.使用自定义的变量来作为标志位

public class ThreadDemo9 {
    public static boolean isQuit = false;

    public static void main(String[] args) {
        // boolean isQuit = false;

        Thread t = new Thread(() -> {
            while (!isQuit) {
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("t 线程终止");
        });

        t.start();

        // 在主线程中, 修改 isQuit
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        isQuit = true;
    }
}

执行结果:

此处代码的逻辑大概就是,主线程sleep ()3秒后,t线程里的循环差不多执行3次(sleep()了3秒),此时isQUit被置为ture,t线程里循环结束.t线程继续向下执行逻辑,最终t线程正常结束.

假设:此处设置的isQuti不是类变量,而是局部变量,可行吗?

结果是显然不行的.那到底是什么原因呢?其实是因为-->lambda表达式存在变量捕获.

变量捕获,只能捕获到由1)final修饰2)实际上final的局部变量.

但是如果该局部变量的值被修改了,那么lamoda表达式就捕获不到该值了.

所以此处该如何做呢? --> 设置成类变量.也就是由static修饰的变量.

因为类变量不受变量捕获的限制.

方法2:使用Thread提供的变量来作为标志位

使用Thread.currentThreadOisInterrupted0 代替自定义标志位.

Thread 内部包含了一个 boolean 类型的变量作为线程是否被中断的标记.

public class ThreadDemo10 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            // currentThread 是获取到当前线程实例.
            // 此处 currentThread 得到的对象就是 t
            // isInterrupted 就是 t 对象里自带的一个标志位.
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t.start();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 把 t 内部的标志位给设置成 true
        t.interrupt();
    }
}

 

原因如下:

首先需要明白interrupt 方法的作用:

1)设置标志位为 true

2)如果该线程正在阻塞中(比如在执行 sleep)此时就会把阻塞状态唤醒.通过抛出异常的方式让 sleep 立即结束.(线程在执行sleep(),join (),wait() 方法时,都会进入阻塞状态)

同时需要注意:
当 sleep 被唤醒的时候, sleep 会自动的把 Thread线程内置的标志位给清空(true -> false).这就导致下次循环,循环仍然可以继续执行了!!!

因此:如果需要结束循环,就得在 catch 中搞个 break.

此处再具体说明一下sleep() 的工作原理:(分3种情况)
1)如果 sleep 执行的时候看到这个标志位是 false --> sleep 正常进行休眠操作.

2)如果当前标志位为 true,sleep 无论是刚刚执行还是已经执行了一半,都会触发两件事 :1.立即抛异常2.清空标志位为 false.
3)如果设置 interrupt 的时候,恰好, sleep 刚醒~~ 这个时候赶巧了,执行到下一轮循环的条件,就直接结束了但是这种概率非常低,毕竟 sleep 的时间已经占据了整个循环体的 99.99999999% 的时间了.几乎可以视为不可能事件.

那可能就又会有人问了,为啥 sleep 要清空标志位呢???
目的就是为了让线程自身能够对于线程何时结束,有一个更明确的控制~
当前interrupt 方法,不是让线程立即结束,而是告诉他,你该结束了,至于他是否真的要结束,立即结束还是等会结束,都是代码来灵活控制的。
interrupt 只是通知,而不是"命令".
为什么这么说呢?原因就是,t线程是否结束,是取决于自身的,也就是说,根据catch里的逻辑实现,可以结束,也可以不结束.

 那肯定又会有人问了:那为啥java 这里 不强制设定成命令结束"的操作? 只要调用 interrupt 就立即结束?? 

主要是设定成这种,非常不友好的~

线程 t 何时结束,一定是 t 自己最清楚~~ 交给 t 自身来决定比较好~~

映射到生活:如果正在跟领导打电话,你的女票让你去帮她拿东西.那此时,肯定是工作优先嘛!!些竟拿东西不是太重要的事,可以先搁置一会!!

3)线程等待

线程之间是并发执行的,操作系统对于线程的调度是无序的.无法判定两个线程谁先执行结束, 谁后执行结束!!!

在某些业务场景下,需要明确规定线程的结束顺序.可以使用线程等待来实现 -->join 方法

public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        Runnable target = () -> {
            for (int i = 0; i < 10; i++) {
                try {
                    System.out.println(Thread.currentThread().getName() 
                                       + ": 我还在工作!");
                    Thread.sleep(1000);
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }
           }
            System.out.println(Thread.currentThread().getName() + ": 我结束了!");
       };
        Thread thread1 = new Thread(target, "李四");
        Thread thread2 = new Thread(target, "王五");
        System.out.println("先让李四开始工作");
        thread1.start();
        thread1.join();
        System.out.println("李四工作结束了,让王五开始工作");
        thread2.start();
        thread2.join();
        System.out.println("王五工作结束了");
   }
}

输出结果:

当前是在main线程里执行的thread1.join()(也就是说是让main线程等待thread1线程).

那么在main线程里执行的thread1.join0 的时候,此时有两种情况:

1)如果 thread线程仍在继续运行,那么main线程就会暂时不参与程调度,等待thread1 线程结束main线程才继续执行代码逻辑.
2)如果thread1线程已经结束,那么main线程也就不用等待了,就直接继续执行自己的代码逻辑了.

但不管是哪种情况,都能保证thread1线程是先于main线程结束的.

4)线程休眠

方法:public static void sleep(long millis) throws InterruptedException

说明:

1)单位是ms

2)sleep是Thread类里的静态方法,通过类名可以直接调用.

3)作用是休眠当前进程.

4)需要用try-catch处理InterruptedException中断异常(意思就是 sleep 睡眠过程中,还没到点就提前唤醒了).

5)获取线程实例

方法:public static Thread currentThread()

说明:在哪个线程里调用,返回的就是哪个线程的对象引用.

public class ThreadDemo {
    public static void main(String[] args) {
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
   }
}

输出结果:main

多提一句:多线程编程在Java中很常见,也很重要.务必掌握!!!

今天不想敲代码,所以才去敲.

uu们加油呀!!

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/1243.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

UDS 14229 -1 刷写34,36,37服务,标准加Trace讲解,没理由搞不明白

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

Windows环境下实现设计模式——状态模式(JAVA版)

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天总结一下Windows环境下如何编程实现状态模式&#xff08;设计模式&#xff09;。不知道大家有没有这样的感觉&#xff0c;看了一大堆编程和设计模式的书&#xff0c;却还是很难理解设计模式&#xff0c;无…

【完整代码】用HTML/CSS制作一个美观的个人简介网页

【完整代码】用HTML/CSS制作一个美观的个人简介网页整体结构完整代码用HTML/CSS制作一个美观的个人简介网页——学习周记1HELLO&#xff01;大家好&#xff0c;由于《用HTML/CSS制作一个美观的个人简介网页》这篇笔记有幸被很多伙伴关注&#xff0c;于是特意去找了之前写的完整…

【高阶数据结构】红黑树

文章目录1. 使用场景2. 性质3. 结点定义4. 结点旋转5. 结点插入1. 使用场景 Linux进程调度CFSNginx Timer事件管理Epoll事件块的管理 2. 性质 每一个节点是红色或者黑色根节点一定是黑色每个叶子节点是黑色如果一个节点是红色&#xff0c;那么它的两个儿子节点都是黑色从任意…

【基础算法】单链表的OJ练习(6) # 复制带随机指针的链表 #

文章目录&#x1f347;前言&#x1f34e;复制带随机指针的链表&#x1f351;写在最后&#x1f347;前言 本章的链表OJ练习&#xff0c;是最后的也是最难的。对于本题&#xff0c;我们不仅要学会解题的思路&#xff0c;还要能够通过这个思路正确的写出代码&#xff0c;也就是思路…

20230314整理

1.JVM内存区域 程序计数器&#xff1a;字节码解释器通过改变程序计数器来依次读取指令&#xff0c;在多线程的情况下&#xff0c;程序计数器用于记录当前线程执行的位置&#xff0c;从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。它的生命周期随着线程的创建而创…

基于Java+SpringBoot+vue的学生成绩管理系统设计和实现【源码+论文+演示视频+包运行成功】

博主介绍&#xff1a;专注于Java技术领域和毕业项目实战 &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案例&#xff08;200套&#xff09; 目录 一、效果演示 二、…

扯什么 try-catch 性能问题?

“yes&#xff0c;你看着这鬼代码&#xff0c;竟然在 for 循环里面搞了个 try-catch&#xff0c;不知道try-catch有性能损耗吗&#xff1f;”老陈煞有其事地指着屏幕里的代码&#xff1a; for (int i 0; i < 5000; i) {try {dosth} catch (Exception e) {e.printStackTrace…

如何测试一个AI系统?

最近AI大火&#xff0c;chatgpt、GPT-4、文心一言不断的在轰炸着我们的生活、工作&#xff0c;很多时候我们都在感叹这智能化来的太快了。对于一个测试工程师&#xff0c;如何开始测试一个AI系统呢&#xff0c;今天我们就一起来聊聊相关的内容。 智能系统对测试工程师提出的新问…

2023年网络安全比赛--网络安全事件响应中职组(超详细)

一、竞赛时间 180分钟 共计3小时 二、竞赛阶段 1.找出黑客植入到系统中的二进制木马程序,并将木马程序的名称作为Flag值(若存在多个提交时使用英文逗号隔开,例如bin,sbin,…)提交; 2.找出被黑客修改的系统默认指令,并将被修改的指令里最后一个单词作为Flag值提交; 3.找出…

React 用一个简单案例体验一遍 React-dom React-router React-redux 全家桶

一、准备工作 本文略长&#xff0c;建议耐心读完&#xff0c;每一节的内容与上一节的内容存在关联&#xff0c;最好跟着案例过一遍&#xff0c;加深记忆。 1.1 创建项目 第一步&#xff0c;执行下面的命令来创建一个 React 项目。 npx create-react-app react-example cd rea…

Springboot集成Swagger

一、Swagger简介注意点&#xff01; 在正式发布的时候要关闭swagger&#xff08;出于安全考虑&#xff0c;而且节省内存空间&#xff09;之前开发的时候&#xff0c;前端只用管理静态页面&#xff0c; http请求到后端&#xff0c; 模板引擎JSP&#xff0c;故后端是主力如今是前…

【宝塔面板部署nodeJs项目】网易云nodeJs部署在云服务器上,保姆级教程,写网易云接口用自己的接口不受制于人

看了很多部署的&#xff0c;要么少步骤&#xff0c;要么就是写的太简洁&#xff0c;对新手不友好 文章目录前言一、下载网易云nodejs项目1. git clone下载&#xff0c;两种方式2. 运行项目二、使用步骤1. 先在本地运行2.测试接口三、部署服务器1. 在宝塔面板安装pm2管理器2. 压…

字符函数和字符串函数【上篇】

文章目录&#x1f396;️1.函数介绍&#x1f4ec;1.1. strlen&#x1f4ec;1.2. strcpy&#x1f4ec;1.3. strcat&#x1f4ec;1.4. strcmp&#x1f4ec;1.5. strncpy&#x1f4ec;1.6. strncat&#x1f4ec;1.7. strncmp&#x1f396;️1.函数介绍 &#x1f4ec;1.1. strlen …

入行 5年,跳槽 3次,我终于摸透了软件测试这行(来自过来人的忠告)

目录 前言 第一年 第二年 第三年 第四年 作为过来人的一些忠告 前言 最近几年行业在如火如荼的发展壮大&#xff0c;以及其他传统公司都需要大批量的软件测试人员&#xff0c;但是20年的疫情导致大规模裁员&#xff0c;让人觉得行业寒冬已来&#xff0c;软件测试人员的职…

【YOLOv8/YOLOv7/YOLOv5/YOLOv4/Faster-rcnn系列算法改进NO.60】损失函数改进为wiou

前言作为当前先进的深度学习目标检测算法YOLOv8&#xff0c;已经集合了大量的trick&#xff0c;但是还是有提高和改进的空间&#xff0c;针对具体应用场景下的检测难点&#xff0c;可以不同的改进方法。此后的系列文章&#xff0c;将重点对YOLOv8的如何改进进行详细的介绍&…

css属性学习

css属性 就是我们选择器里面 { } 中的内容 字体样式 font-size 控制字体大小&#xff1a;单位px&#xff08;像素&#xff09; 默认字体占16个像素 <p style"font-size:30px;">font-size&#xff1a;字体大小&#xff0c;单位的话可以用px表示占的像素个数&…

Mini-Xml 经典实例Demo

欢迎小伙伴的点评✨✨&#xff0c;相互学习、博主将自己研发xml微型服务器的经验与之分享&#x1f30f;&#x1f30f;&#x1f642; 文章目录前言一、使用mxml库编写Xml文件1.1 经典实例Demo_11.2、经典实例Demo_21.3、经典实例Demo_3二、总结前言 本章将会给大家带来mini-xml…

在我的MacBook上捣鼓ESP8266

周三是我们的篮球日&#xff0c;打篮球后总是会有些兴奋&#xff0c;然后就容易睡不着&#xff0c;额&#xff0c;睡不着就拿我的ESP8266开发板出来捣鼓一下。先下载编译工具链https://github.com/espressif/ESP8266_RTOS_SDK下载sdkgit clone https://github.com/espressif/ES…

C++程序在内存中的模型

进程&#xff08;Process&#xff09;是计算机中的程序&#xff0c;数据集合在其上运行的一次活动&#xff0c;是系统进行资源分配的基本单位。每个进程都有自己独立的虚拟内存地址空间&#xff0c;这个虚拟的内存地址空间一般是线性连续的&#xff0c;这个内存地址空间是虚拟的…