多线程的创建,复习匿名内部类,Thread的一些方法,以及lambda的变量捕捉,join用法

news2024/11/29 0:38:43

一、💛 

Java的Thread类表示线程

1.创建类,继承Thread重写run方法

2.创建类,实现Runnable重写run方法

3.可以继承Thread重写run基于匿名内部类

4.实现Runnable重写run基于匿名内部类

5.lamdba表达式表示run方法的内容(推荐)

6。基于Callable(以后学)

7.基于线程池(以后学)

 匿名内部类(不用看定义,看下面用法领悟):正常建类后面大括号,这一步相当于先创建一个子类,但是这个子类是没有名字(匿名),另一方面,这类的创建是在Demo这个类里面。

下面这个写法是3号💛💛

我们要记住一个是,最重要的是写run这个是赋予了线程需要做什么工作。

public  class  Demo {
        public static void main(String[] args) throws InterruptedException {
            Thread t=new Thread(){      //匿名内部类,看上面详细解答
                @Override
                public void run() {     //子类中重写了run方法,实现了线程要干的工作
                    while(true){
                        System.out.println("hello world");
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            t.start();               //创建了该类的实例,并且是使用那个t这个引用指向。
            while (true) {
                System.out.println("love");
                Thread.sleep(1000);
            }
        }
    }

写法4😃😃

为什么括号不是封死的,因为小括号对应的是Thread构造方法的结束,new Runnable整个一段,都在构造出一个Thread的参数, 创建这个匿名内部类,通过构造方法传给Thread。

public  class  Demo {
        public static void main(String[] args) throws InterruptedException {
            Thread t=new Thread(new Runnable (){            //!!!括号不是封死的
                @Override
                public void run() {
                    while(true){
                        System.out.println("hello world");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }   ) ;                 //!!!!!看这个小括号
            t.start();
            while (true) {
                System.out.println("love");
                Thread.sleep(1000);
            }
        }
    }

5.使用lambda(推荐的方法) 表示run方法的内容😗😗 (本质是匿名方法,这样的匿名函数,主要可以作为回调函数使用。——回调函数(合适的时候就干,不合适就选择不干。),不需要程序猿们主动去调动(需要知道函数名,才能被调动,常用场景 1.服务器开发 2.图形界面开发,用户的某个操作,触发回调),而是在合适的时机自动的被调动

Java本身不允许函数脱离类,但是lambda特例,起名叫“函数式接口”(😊必须只有一个方法😊)

类似于Lammbda这样的写法,本质上并没有新增新的语言特性,而是把以往实现的功能,换了一种更简单的方式编写。

public  class  Demo {
        public static void main(String[] args) throws InterruptedException {
            Thread t=new Thread(()->{                //也是没有右括号,在下面。
                    while(true){
                        System.out.println("hello world");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
            });
            t.start();
            while (true) {
                System.out.println("love");
                Thread.sleep(1000);
            }
        }
    }

二、 💚 

Thread就是Java,线程的代言人,系统中一个线程,对应Java中一个Thread对象

public  class  Demo {
        public static void main(String[] args) throws InterruptedException {
            Thread t=new Thread(()->{
                    while(true){
                        System.out.println("hello world");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
            },"myThread");           //给这个进程起名字
            t.start();
            while (true) {
                System.out.println("love");
                Thread.sleep(1000);
            }
        }
    }

Thread常见ID。线程的身份标识(JVM,给设定了一个标识)

一个线程可以存好几个身份标记:

1.JVM有一个身份标记

2.pthread库(系统给程序猿提供的操作线程的API,也有一个线程的身份标识)

3.内核里面,针对线程的PCB还有身份标识

Thread常见属性

id.           getId()                            

name.     getname()

状态。     getState()           java中线程的状态和操作系统的有一定差异。

优先级     getPriority          设置获取优先级的作用不是很大,线程的调度,主要还是系统内核负责~系统的调度速度更快。

是否是后台进程   isDaemon()          

后台进程/守护进程,后台进程不影响进程结束,(创建的线程默认是前端线程)前台进程会影响到进程结束,如果前台进程没执行完,进程是不会结束的。

一个进程的所有前台线程,都执行完退出了,那么即使存在后端线程没有执行完毕,也会随着进程一起退出

setDaemon(true)   把某一个进程,设置为后端进程,这样前端线程结束,后面的也结束了

public  class  Demo {
        public static void main(String[] args) throws InterruptedException {
            int n =0;
            Thread t=new Thread(()->{
                    int m =0;
                    while(m<9){
                        System.out.println("hello world");
                        m++;
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
            },"myThread");
            t.setDaemon(true);             //设置为后端线程

            t.start();
            while (n<3) {           // 打印完事走完全部就结束了,所以一定会有这三个
               System.out.println("love");    
                n++;
                Thread.sleep(1000); 
            }
        }
    }

是否存活 isAlive

Thread对象,对应的线程(在系统内核中)是否存活。

Thread对象,并不是和系统中的线程完全一样(同生共死)的。

一般的Thread对象,先创建好,~手动调用start ,内核才真正创造出线程

消亡的时候,

可能对象,先结束了生命周期(没有引用指向这个对象)

也有可能Thread对象还在,内核中的线程把run执行完成了,就结束了。

对象的整个生命周期大致可以分为7个阶段:

创建阶段、应用阶段、不可视阶段、不可到达阶段、可收集阶段、终结阶段、与释放阶段(了解就好)

重要方法start():真正创造出线程->调用系统API完成线程创建工作(本身是一瞬间完成的,相当于是传话的小弟,“你造个线程出来😈”,调用API之后代码立刻执行start之后的逻辑

操作系统=内核+配套的程序

一个系统最核心的功能:

1.对下管理好各种硬件设备

2.对上,给各种程序提供稳定的运行环境

操作系统的内核(应用程序):

创建线程,非常核心的功能,系统API,系统调用

一般情况应用,不可进入内核操作,不可进入内核的程序成为“用户态”

如果一些应用程序,能够进入后台,直接操作内核里面的一些数据结构,程序是出于“内核态”这样的程序还叫做驱动程序


、💙  

Thread的方法💙 

(一个线程的run方法执行完毕,就算终止了。此时的终止此处线程,就是要想办法让run尽快执行完毕(正常不会出现run没执行完毕,突然就没了的情况)

(sleep相当于是停一会,不是说停止了)

1.程序猿们手动设置标志位,如

public static voolean isQuit=false;(写成成员变量,不会触发变量捕捉,而是内部类来访问成员变量, 看下面这个图,代码在后面,执行完isQuit=true; 线程就终止了,同时main也走完了。

public  class  Demo {
    public static boolean isQuit=false;
        public static void main(String[] args) throws InterruptedException {
            int n =0;
            Thread t=new Thread(()->{
                    int m =0;
                    while(!isQuit){
                        System.out.println("hello world");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
            },"myThread");

            t.start();

            while (n<3) {
                System.out.println("love");
                n++;
                Thread.sleep(1000);
            }
            isQuit=true;          //手动终止
        }
    }

但是我们来看下面这个图,为什么我这样放进方法里面不可以呢?——这就源于我们lambda表达式的变量捕捉机制​​​​​​​~

lambda可以捕获外界变量,这样lambda表达式执行的时机是更靠后的,这就导致,后续真正执行lambda时候,局部变量isQuit是否可能已经被销毁了呢?

这种情况是客观存在的,让lambda去访问一个已经被销毁的变量,很明显是不合适的,lambda引入了变量捕获这样的机制~,lambda去访问一个已经被销毁的变量,但明显是不合适的,lambda引入了变量捕获这样的机制~,lambda内部看起来是直接访问外部的变量,其实本质是把外部变量给复制了一份,到lambda里面(这样就可以解决刚才的生命周期问题了)(但是捕获变量有限制的,要求是be final(如同final,就是一个变量,我们后续没有修改他的操作)  or effectively final(事实上的最终值 final修饰)

2.直接用Thread 类,给我们提供了现成标志位,不用手动, 🐶

while(!Thread.currentThread().isInterrupted())

Thread.currentThread():的含义获取当前线程的对象Thread,提供静态方法,currentThread在哪个线程调动这个方法,就能够获取到哪个线程的引用(相当于就是t,但是不可以写t,写t是报错的)

isInterrupted()

对象内部,提供了一个标志位(boolean类型的)

true:结束

false:不结束

我们看上面的图能发现,为啥还会有异常呢?🐹,原因就是一个线程kennel正在运行,也可能处于sleep状态,如果线程sleep的过程中,是否应该把他唤醒你?

当然了,肯定要把他唤醒,但是sleep在唤醒的同时也会自动清除前面设置的标志位,给程序猿们留下操作空间,此时要是想让线程结束,则catch之后加一个break;

sleep唤醒之后,程序猿们一般有以下几种操作方式:

1.立即停下来,立即结束线程

2.忽略终止请求,继续循环(不写break)

3.继续做点别的事情,过一会再结束线程(catch之后执行别的逻辑,最后break;)

 

public  class  Demo {

        public static void main(String[] args) throws InterruptedException {
            int n =0;
            Thread t= new Thread(()->{
                    int m =0;
                    while(!Thread.currentThread().isInterrupted()){
                        System.out.println("hello world");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            break;
                        }
                    }
            },"myThread");

            t.start();

            while (n<3) {
                System.out.println("love");
                n++;
                Thread.sleep(1000);
            }
           t.interrupt();
        }
    }

四、💗 

等待线程——join

多个线程是并发执行的,具体的执行过程,都是由操作系统复制调度的!!!,操作系统的调度线程“随机的”(当然,是我们无法确定他的先后顺序)

等待线程就是一种规划线程结束顺序的手段~ A,B两个线程,希望B先结束,A后结束,此时就可以,让A线程调用B.join方法(去等待B)

此时B线程还没结束完,A线程就会进入阻塞状态,相当于给B留下了空间,B执行完毕之后,A再从阻塞状态中恢复回来,并且继续往后执行。,如果A执行到B.join的时候,B已经执行完,那么A就不用阻塞了,直接往下执行即可,如下图,他是等待,先把t这个线程走完了,再去走下面的main.

​​​​​​​

阻塞->该代码暂时不继续执行(该进程暂时不去cpu参与调度)sleep也能让该线程阻塞,但是是有时间限制的

join是死等,知道你完事,不然他不会开始(不推荐) 产生一个新的join(里面填写时间)最大等待时间。只要我时间到了,不管你来不来,我都走了(更推荐使用,这种时间版本,留有余地。)

可以被interrupt唤醒的等待操作:

1.join

2.sleep

3.wait

 需要的自己拿着用呗

public  class  Demo {

        public static void main(String[] args) throws InterruptedException {
            int n =0;
            Thread t= new Thread(()->{
                    int m =0;
                    while(m<5){
                        System.out.println("hello world");
                        m++;
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
            },"myThread");

            t.start();
            t.join(3000);
            while (n<3) {
                System.out.println("love");
                n++;
                Thread.sleep(1000);
            }

        }
    }

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一、安全世界观

文章目录 1、 Web安全简史1.1 中国黑客简史1.2 黑客技术的发展历程1.3 web安全的兴起 2、黑帽子、白帽子3、安全的本质4、安全三要素5、如何实施安全评估5.1 资产等级划分5.2 威胁分析5.3 风险分析5.4 设计安全方案 6、白帽子兵法6.1 Secure By Default6.2 纵深防御原则6.3 数据…

在Raspberry Pi 4上安装Ubuntu 20.04 + ROS noetic(不带显示器)

在Raspberry Pi 4上安装Ubuntu 20.04 ROS noetic&#xff08;不带显示器&#xff09; 1. 所需设备 所需设备&#xff1a; 树莓派 4 B 型 wifi microSD 卡&#xff1a;最小 32GB MicroSD 转 SD 适配器 &#xff08;可选&#xff09;显示器&#xff0c;鼠标等 2. 树莓派…

积累常见的有针对性的python面试题---python面试题001

1.考点列表的.remove方法的参数是传入的对应的元素的值,而不是下标 然后再看remove这里,注意这个是,删除写的那个值,比如这里写3,就是删除3, 而不是下标. remove不是下标删除,而是内容删除. 2.元组操作,元组不支持修改,某个下标的内容 可以问他如何修改元组的某个元素 3.…

Git Submodule 更新子库失败 fatal: Unable to fetch in submodule path

编辑本地目录 .git/config 文件 在 [submodule “Assets/CommonModule”] 项下 加入 fetch refs/heads/:refs/remotes/origin/

sigmoid ReLU 等激活函数总结

sigmoid ReLU sigoid和ReLU对比 1.sigmoid有梯度消失问题&#xff1a;当sigmoid的输出非常接近0或者1时&#xff0c;区域的梯度几乎为0&#xff0c;而ReLU在正区间的梯度总为1。如果Sigmoid没有正确初始化&#xff0c;它可能在正区间得到几乎为0的梯度。使模型无法有效训练。 …

如何让子组件,router-view,呈现左右分布格局

1.用浮动进行浮动布局&#xff0c;定义一个大盒子&#xff0c;把浮动的样式写在公共样式里&#xff08;这里在main.js里定义一下全局布局&#xff09;。 2、能够在右边显示了

小研究 - MySQL 分区分表的设计及实(一)

随着信息技术的快速发展&#xff0c;数据量越来越大&#xff0c;海量的表查询操作需要消耗大量的时间&#xff0c;成为影响数据库访问性能提高的主要因素。为了提升数据库操作的查询效率和用户体验&#xff0c;在关系型数据库管理系统(MySQL)中通过 range 分区和 Merge 存储&am…

因果推断(三)双重差分法(DID)

因果推断&#xff08;三&#xff09;双重差分法&#xff08;DID&#xff09; 双重差分法是很简单的群体效应估计方法&#xff0c;只需要将样本数据随机分成两组&#xff0c;对其中一组进行干预。在一定程度上减轻了选择偏差带来的影响。 因果效应计算&#xff1a;对照组y在干预…

【kafka消息查询】kafka消费不到数据,写入端伙伴说他写入了,而且没有报错,如何来切割是写入的问题还是消费的问题

文章目录 前言情景再现如何确定是否写入了为什么出现不能写入总结 前言 kafka消费不到消息&#xff0c;如何查询界定是生产端的问题还是消费端的问题&#xff0c;特别是场景上下文已经丢失了的时候。 情景再现 使用命令&#xff1a; bin/kafka-console-consumer.sh --bootstr…

前端js用正则写一个车牌号验证

var car_number2 (rule, value, callback) > {var plateNumber /^([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏…

simpleNet

文章目录 simpleNet0. 背景1. 主要贡献2. 网络3. 方法细节3.1 Feature Extractor 特征提取器3.2 Features Adaptor特征适配器3.3 Anomalous Feature Generator 异常特征生成器3.4 Discriminator 鉴别器3.5 Loss function and Training 损失方程和训练3.6 Inference and Scoring…

网信办制定个人信息保护新规,企业应采取哪些举措实现身份审计合规

近日&#xff0c;国家互联网信息办公室就《个人信息保护合规审计管理办法&#xff08;征求意见稿&#xff09;》面向社会公开征求意见。征求意见稿指出&#xff0c;办法根据《中华人民共和国个人信息保护法》等法律法规制定&#xff0c;旨在指导、规范个人信息保护合规审计活动…

K8s的高可用搭建

高可用技术搭建 在master节点上需要部署&#xff1a;keepalived、haproxy

记一款开源免费的终端工具Tabby

经常需要在Windows电脑上远程操作Linux&#xff0c;常用的终端工具有Xshell、SecureCRT、Putty。其中Xshell和SecureCRT功能强大&#xff0c;但是要收费&#xff0c;Putty虽然免费&#xff0c;但是功能上略显单薄。今天给大家介绍的这款终端工具非常强大&#xff0c;他不仅界面…

怎么样通过Bootstrap已经编译好(压缩好)的源码去查看符合阅读习惯的源码【通过Source Map(源映射)文件实现】

阅读本篇博文前&#xff0c;建议大家先看看下面这篇博文&#xff1a; https://blog.csdn.net/wenhao_ir/article/details/132089650 Bootstrap经编译(压缩)后的源码百度网盘下载地址&#xff1a; https://pan.baidu.com/s/14BM9gpC3K-LKxhyLGh4J9Q?pwdm02m Bootstrap未经编译…

【Spring专题】Spring底层核心原理解析

前言 Spring啊&#xff0c;可以说是我们大部分Java玩家【最熟悉的陌生人】了吧。八个字形容&#xff1a;似懂非懂&#xff0c;会也不会 你说简单应用&#xff0c;我们大家都会&#xff0c;那真要展开说两句的话&#xff0c;那只能来这么两句&#xff1a;这是第一句&#xff0…

C高级 作业 day4 8/7

1.整理思维导图 2.写一个函数&#xff0c;获取用户的uid和gid并使用变量接收 3.整理冒泡排序、选择排序和快速排序的代码 冒泡排序 //冒泡排序 void bubble_sort(int a[],int len) {int count0;for(int i1;i<len;i) //控制轮数{for(int j0;j<len-i;j) //控制每一轮交换…

opencv基础-29 Otsu 处理(图像分割)

Otsu 处理 Otsu 处理是一种用于图像分割的方法&#xff0c;旨在自动找到一个阈值&#xff0c;将图像分成两个类别&#xff1a;前景和背景。这种方法最初由日本学者大津展之&#xff08;Nobuyuki Otsu&#xff09;在 1979 年提出 在 Otsu 处理中&#xff0c;我们通过最小化类别内…

代码随想录—力扣算法题:977有序数组的平方.Java版(示例代码与导图详解)

版本说明 当前版本号[20230807]。 版本修改说明20230807初版 文章目录 版本说明977.有序数组的平方思路暴力排序双指针法 两种方法的区别 总结 977.有序数组的平方 力扣题目链接 更多内容可点击此处跳转到代码随想录&#xff0c;看原版文件 给你一个按 非递减顺序 排序的整…

NodeJs执行Linux脚本

&#xff08;我们活着不能与草木同腐&#xff0c;不能醉生梦死&#xff0c;枉度人生&#xff0c;要有所作为。——方志敏&#xff09; 为什么需要使用NodeJs执行Linux脚本 linux的sh脚本命令编写复杂&#xff0c;在不熟悉linux交互式命令的情况下&#xff0c;使用高级编程语言…