JAVA----Thread

news2024/9/19 10:39:36

Thread

这里写目录标题

  • Thread
    • 线程
      • Thread 第 1 种写法
        • 此外, t.start()的作用
      • Thread 第 2 种写法
      • Thread 第 3 种写法
      • Thread 第 4 种写法
      • Thread 第 5 种写法

线程

本身是操作系统提供的, 操作系统提供了 API 以让我们操作线程, JVM 就对操作系统 API 进行了封装.
线程这里, 则提供了 Thread 类, 表示线程. 利用类中的创建的实例, 以及实例里面创建的一系类方法, 我们就可以完成多线程编程了.

Thread 第 1 种写法

代码示例

package thread;
class MyThread extends Thread{
    //注解: 相当于是 提示编译器, 进行更严格的检查
    @Override
    public void run() {
        //run(): 描述线程的工作
        System.out.println("hello thread");
    }
}

public class Demo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
    }
}

结果

hello thread

Process finished with exit code 0//进程结束

上述代码中, 有 2 个线程:

  1. t 线程;
  2. main 方法所在的线程 (主线程).

但以上执行, 无法很直观的看见两个线程的执行, 我们再对其进行修改.
代码如下

package thread;
class MyThread extends Thread{
    //注解: 相当于是 提示编译器, 进行更严格的检查
    @Override
    public void run() {
        //run(): 描述线程的工作
        while(true){
            System.out.println("hello thread");
        }
    }
}

public class Demo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
        while(true){
            System.out.println("hello main");
        }
    }
}

运行结果是两者交替 并发 执行.

我们可以使用 jdk 中包含的 jconsole 工具来观察线程.

在这里插入图片描述
thread.Demo1则是我们创建的线程, 选中连接.

在这里插入图片描述
再点击 线程

在这里插入图片描述
我们可以看到, 执行一个文件, 有 15 个线程, 并且在下方能看见 main 和 Thread-0 两个线程.

我们分别点击main 与 Thread线程
在这里插入图片描述
在这里插入图片描述
如图, 我们可以看到线程的调用栈, main 在调用sleep() 方法, Thread 有一个run() 方法在调用sleep().

我们同样可以打开任务管理器

在这里插入图片描述

我们可以看见这一个 循环, 吃了很多的CPU资源

故而我们利用 sleep() 方法, 来让线程主动进入"阻塞状态", 主动离开 CPU, 睡眠 / 休眠 一段时间.

try {
    Thread.sleep(1000);//休眠1秒(单位 ms)
} catch (InterruptedException e) {
    throw new RuntimeException(e);
}

等时间到了之后, 线程就会解除 “阻塞状态”, 重新被调度到 CPU 上执行.

package thread;
class MyThread extends Thread{
    //注解: 相当于是 提示编译器, 进行更严格的检查
    @Override
    public void run() {
        //run(): 描述线程的工作
        while(true){
            System.out.println("hello thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new MyThread();
        t.start();
        while(true){
            System.out.println("hello main");
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述
此时的 CPU 占用率大幅降低.

此时涉及到一个问题
在未来实际开发中, 发现服务器程序, 消耗 CPU 资源超出预期, 如何排查这个问题.

则 先需要确认哪个线程消耗的 CPU 比较高: 利用第三方工具找到此线程, 确定以后, 进一步 排查 线程中是否有类似 “非常快速” 的循环.
然后确认 此循环是否应该这么快, 若应该, 则升级 CPU. 若不应该, 则需要在循环中引入 等待操作(不一定是sleep() ).

然而
每个线程打印可能是 main 在前, 也可能是 thread 在前, 多个线程的调度是无序的, 在操作系统内部也称为 “抢占式执行”. 充满了随机性, 正是如此, 使用多线程是难以预测的.

此外, t.start()的作用
package thread;
class MyThread extends Thread{
    //注解: 相当于是 提示编译器, 进行更严格的检查
    @Override
    public void run() {
        //run(): 描述线程的工作
        while(true){
            System.out.println("hello thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new MyThread();
//      t.start();
        
        t.run();
        //这里则是没有创建线程, 就是在主线程中执行上述 run 中的循环打印.
        while(true){
            System.out.println("hello main");
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

t.start() (Thread类中自带的方法):
调用 操作系统 提供的"创建线程" api,
在内核创建对应的 pcb 加入到链表中,
进一步的系统调度到这个线程了之后,
就会执行上述 run 方法中的逻辑.

当我们运行时, 只能看见起循环 Thread线程 内的打印操作, 而看不见 main线程 的打印操作.
此时的 run 和 主线程的循环是 串行执行, 不是 “并发执行”. 必须要求 run 中的循环结束, 才能继续执行到下一个循环.

像以上的 run, 定义好,而不去手动调用, 把这个方法交给系统/其他的库/其他框架调用.这样的方法称为: “回调函数”(callback function).

java数据结构, 谈到了比较强, 类似于 回调函数 的效果. PriorityQueue 优先级队列.

多线程 run 方法, 和上述两个情况本质一样, 都是回调函数.

Thread 第 2 种写法

package thread;
//Runnable: 描述一个任务
class MyRunnable implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("hello thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Demo2 {
    public static void main(String[] args){
        Thread t = new Thread(new MyRunnable());
        t.start();
        while (true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

第一种写法, 是 Thread 自己记录自己的操作.
第二种写法, 是 Runnable 记录操作, Thread 负责执行.

当运行内容 与 执行 两个操作分离开, 实现了解耦合操作.
在java中 解耦合 使用接口实现.

解耦合的作用: 简单来讲, 就是使代码的维护难度降低.

Thread 第 3 种写法

package thread;

public class Demo3 {
    public static void main(String[] args) {
        Thread t = new Thread(){
            /*这里的 new Thread 并非是 new 一个 Thread, 而是几个操作融合在了一起
            1. 创建了一个 Thread的子类(匿名的)
            2. 同时创建了一个该子类id实例, 对于匿名内部类只能创建这一个实例,
            这个实例创建完之后, 再也拿不到这个匿名内部类了.
            3. 此处的子类内部重写了父类 run 方法.
            */
            @Override
            public void run() {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t.start();
        while(true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Thread 第 4 种写法

package thread;

public class Demo4 {
    public static void main(String[] args) {
        //Runnable 匿名内部类,
        //此处匿名内部类,只针对 Rnunable,与 Thread 无关
        //把 Runnable 实例, 作为参数传入到 Thread 的构造方法内
        Thread t = new Thread(new Runnable() {
            /*1.创建新的类, 实现Runnable.但类名是匿名的.
            2.同时创建了这个新类的实例(一次性)
            3.重写run方法*/
            @Override
            public void run() {
                while(true){
                    System.out.println("hello thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
            t.start();
            while(true){
                System.out.println("hello main");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

Thread 第 5 种写法

lambda 表达式

package thread;
//使用 lambda 表达式
public class Demo5 {
    public static void main(String[] args) {
        //此处的 lambda 就是要代替Demo4重写的 run方法
        Thread t = new Thread(() -> {
            System.out.println("hello Thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        t.start();
        while(true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

以上 5 种 方法,本质上都是
1.要把线程执行的任务内容表达出来.
2.通过 Thread 的 start 来创建/启动系统种的线程.
(Thread 对象和操作系统内核中的线程是 一 一 对 应 的关系)

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

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

相关文章

verilog变量类型wire、reg和Memory的介绍和用法

目录 wire型 reg型 Memory型 wire型 wire 类型变量,也叫网络类型变量,用于结构实体之间的物理连接,如门与门之间,不能储存值,用连续赋值语句 assign 赋值,定义为 wire [n-1:0] a ; 其中 n 代表位宽&…

OCT2Former: A retinal OCT-angiography vessel segmentationtransformer论文总结

论文(COMPUT METH PROG BIO):OCT2Former: A retinal OCT-angiography vessel segmentation transformer 源码:https://github.com/coreeey/OCT2Former 一、摘要 背景与目的:视网膜血管分割在视网膜疾病自动筛查与诊断中起着重要作用。如何分…

面试高频:HTTPS 通信流程

更多大厂面试内容可见 -> http://11come.cn 面试高频:HTTPS 通信流程 HTTPS 的加密流程 接下来说一下 HTTPS 协议是如何进行通信的: HTTPS 通信使用的 对称加密 非对称加密 两者结合的算法 HTTPS 通信时,会先使用 非对称加密 让通信双…

大sql mysql执行

先把sql 拆分 太大的执行失败 使用 SQLDumpSplitter3 拆分sql 执行拆分的sql 拆分的sql 打开发现很多 ; 开头的空行 替换掉 正则 ^; 修改数据库 my.cnf my,ini 执行可能会提示 [ERR] 2006 - Server has gone away 错误 在 [mysqld] 添加以下几行 wait_timeout2880000 inter…

Qt基础之四十六:Qt界面中嵌入第三方程序的一点心得

本文主要讲解QWidget和QWindow的区别,以及如何在QWidget中嵌入第三方程序,并完美解决在QWidget中嵌入某些程序(比如Qt程序)时出现的白边问题。 下面是嵌入QQ音乐的样子,这首歌还不错。 先用spy++查看QQ音乐的窗口信息,如果安装了Visual Studio,工具菜单里自带spy++ 然后…

【1471】java项目进度管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java 项目进度管理系统是一套完善的java web信息管理系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql5.0&…

【Linux】自定义协议——实现网络序列化和反序列化

欢迎来到Cefler的博客😁 🕌博客主页:折纸花满衣 🏠个人专栏:题目解析 🌎推荐文章:承接上文内容【Linux】应用层协议序列化和反序列化 目录 👉🏻代码实现如下Calculate.hp…

企业常用Linux三剑客awk及案例/awk底层剖析/淘宝网cdn缓存对象分级存储策略案例/磁盘知识/awk统计与计算-7055字

高薪思维: 不愿意做的事情:加班,先例自己在利他 生活中先利他人在利自己 感恩,假设别人帮助过你,先帮助别人,感恩境界 awk三剑客老大 find其实也算是一种新的第四剑客 find 查找文件 查找文件,与其他命令…

【UnityShader】图片圆角

1.需求 我们在开发的时候,有时候一些按钮或者菜单栏的边角是直角的需要改成圆角,但是让美术重新绘制耽误时间不说也确实没必要,这个时候我们不妨使用一个简单的shader去解决这个问题,下面我们就讲讲这个shader要如何实现。 需求1…

设计模式之观察者模式(优先使用对象组合的原则)的C++实现

观察者模式又称订阅者发布者模式,本篇介绍主要是利用对象组合大于类继承的设计模式原则实现订阅发布模式,这种设计的优点是想订阅数据的类不需要继承订阅者类的抽象类,减少了一层类的继承;当然,具体情况需要可根据需求…

在ios设备上运行Unity Profiler

久违了朋友们。 最近基于Unity 2021.3 和AR Foundation开发了个应用,需要在ipad上实际运行时查看程序的各项指标功耗。 于是乎,我尝试跟随者官方教程来实时调试,现在附上一些心得。 按照官方的三步走,Build and Run理论上会自动…

42岁TVB男艺人曾靠刘德华贴钱出道,苦熬10年终上位

张颕康在无线(TVB)电视打滚多年,近年在《逆天奇案》第一、二辑凭扎实演技为人留下印象。他还是圈中出名的「爱妻号」,日前在访问期间,张颕康三句不离多谢太太。 较年长的观众或会记得,张颕康初出道以「刘德…

边缘计算智能分析网关V4地面垃圾AI检测算法介绍及场景应用

在传统的卫生监管场景中,无法及时发现地面遗留的垃圾,通过人工巡逻的方式需要大量的人力、物力和时间,而且效率不高,并存在一定的滞后性,而采用地面垃圾AI检测算法则可以大大提高监管效率。 TSINGSEE青犀AI智能分析网…

骑砍2霸主MOD开发(6)-使用C#-Harmony修改本体游戏逻辑

一.C#-Harmony反射及动态注入 利用C#运行时环境的反射原理,实现对已加载DLL,未加载DLL中代码替换和前置后置插桩. C#依赖库下载地址:霸王•吕布 / CSharpHarmonyLib GitCodehttps://gitcode.net/qq_35829452/csharpharmonylib 根据实际运行.Net环境选择对应版本的0Harmony.dll…

【编译原理】03语法分析

1,语法分析的若干问题 1.1 语法分析器的作用 编译器前端的重要组成部分: (1) 根据词法分析器提供的记号流,为语法正确的输入构造分析树(或语法树)。 (2) 检查输入中的语法(可能包括词法)错误,并调用出错处理器进…

MyBatis 核心配置讲解(上)

大家好,我是王有志,一个分享硬核 Java 技术的互金摸鱼侠。 前两篇的文章中我们分别介绍了 MyBatis 和 MyBaits 的应用组成,到这里基础篇的内容就结束了。 从今天开始,我们正式进入 MyBatis 学习的第二阶段:MyBatis 的…

插值与重采样在AI去衣技术中的关键作用

在人工智能(AI)的众多应用中,去衣技术作为一种新兴的图像处理技术,逐渐引起了广泛关注。这项技术不仅涉及复杂的计算机视觉和深度学习算法,还需要对图像处理中的插值与重采样技术有深入的理解。本文将详细探讨插值与重…

【笔试训练】day7

1.在字符串中找出连续最长的数字串 思路&#xff1a; 简单双指针&#xff0c;随便怎么暴力 代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> #include<string> using namespace std;int main() {string str;cin >> str;int ans …

微服务之SpringCloud AlibabaNacos服务注册和配置中心

一、概述 1.1注册中心原理 在微服务远程调用的过程中&#xff0c;包括两个角色&#xff1a; 服务提供者&#xff1a;提供接口供其它微服务访问&#xff0c;比如item-service 服务消费者&#xff1a;调用其它微服务提供的接口&#xff0c;比如cart-service 在大型微服务项目…

Laya2.13.3 Texture和Teture2D的关系,怎样将Texture2D转换为Texture。

Texture是是纹理处理类&#xff0c;Sprite和Image上显示的图像都是经Texture处理的&#xff0c; Texture2D是3d模型纹理贴图的处理类&#xff0c;用于显示3D模型的纹理细节。 如何将Textture2D转换为Texture&#xff0c;Texture的API接口如下&#xff1a; 可以看到Texture首先…