Java线程 - 详解(1)

一,创建线程

方法一:继承Thread类

class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("线程1");
    }
}

public class Test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();//start()方法启动线程

        //和上面的方法一样,只不过使用匿名内部类实现
        Thread thread1 = new Thread(){
            @Override
            public void run() {
                System.out.println("线程2");
            }
        };
        thread1.start();

    }
}

方法二:实现Runnable接口

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程1");
    }
}
public class Test {
    public static void main(String[] args) {

        Thread thread = new Thread(new MyRunnable());
        thread.start();
        
        //匿名内部类实现
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程2");
            }
        });
        thread2.start();

        //lambda表达式实现
        Thread thread3 = new Thread(() -> System.out.println("线程3"));
        thread3.start();

    }
}

二,Thread类及常见方法

2.1 构造方法

方法说明
Thread()创建线程对象
Thread(Runnable  target)使用Runnable对象创建线程对象
Thread(String  name)创建线程对象并命名
Thread(Runnable  target,String  name)使用Runnable对象创建线程对象,并命名
Thread(ThreadGroup  group,Runnable  target)线程可以被用来分组管理,分好的组即为线程组(了解即可)

2.2 获取 Thread 的常见属性

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  • ID是线程的唯一标识,ID是JAVA分配的,不会出现重复的,与上篇博客中PCB结构中的pid不是同一个东西。
  • 名称是方便各种调试工具使用。
  • 后台线程不会影响线程的结束,前台线程会影响线程的结束,一般线程默认为前台线程,还有一个注意点——JVM会在一个进程的所有后台进程结束后,才会结束运行。
  • 是否存活,简单理解就是 run 方法是否运行结束。
public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            System.out.println("线程开始");
            try {
                Thread.sleep(1000);//休眠线程 xxx ms
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        },"1号线程");
        thread.setDaemon(true);//设置为后台线程
        thread.start();
        System.out.println(thread.getName() + " " + thread.isAlive());
        Thread.sleep(3000);
        System.out.println("线程结束");
        System.out.println(thread.isAlive());
    }
}

 

2.3 start()  与  run() 的区别

作用功能:

  1. start()方法内部是会调用系统的API,在系统内核创建一个线程
  2. run()方法只是描述线程具体实现的任务(会在start创建好之后会自动被调用)

运行结果:

  1. start调用方法后, start方法内部会调用Java 本地方法(封装了对系统底层的调用)真正的启动线程,并执行run方法中的代码,run 方法执行完成后线程进入销毁阶段。
  2. run方法是一个类中的普通方法,主动调用和调用普通方法一样,会顺序执行一次

 2.4 中断一个线程

在Java中,终止/销毁一个线程的做法比较单一,就是尽快让 run 方法执行结束。

方法一: 在代码中手动创建一个标志位,来作为 run 的执行结束条件,比如在很多线程中,执行时间长往往是写了一个循环。

public class Demo {
    private static boolean isQuit = false;//通过类属性来控制
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            while (!isQuit){
                System.out.println("666");
            }
        });
        thread.start();
        Thread.sleep(1);
        isQuit = true;
    }
}

 注:这里的 isQuit 不能是局部变量,因为如果是局部变量就不满足 lambda表达式中的变量捕获语法。

但是上面的方法有两个缺点:1. 需要手动创建变量 2. 当线程内部在 sleep 的时候,主线程修改变量时,新线程内部不能及时响应,所以Java提供了另一种解决方法:

方法二:使用 interupt() 和 isInterrupted()

方法说明
public void interrupt()中断对象关联的线程,如果线程阻塞,则以异常方式通知,否则设置标志位
public static boolean interrupted()判断当前线程中的标志位是否设置,调用后清除标志位
public boolean isInterrupted()判断对象关联的线程的标志位是否设置,调用后不清除标志
public class Demo {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            // Thread.currentThread()作用是得到当前的线程
            // isInterrupted() 判断标识符是否为false
            //或者 while(!Thread.interrupted()) 效果一样
           while(!Thread.currentThread().isInterrupted()){
               System.out.println("线程工作中!");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();//打印异常
               }
           }
        });
        thread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();//将标识符设置为true
    }
}

但是报错后,该线程没有中断,而是继续执行,这是为什么呢?

这是因为当我们将 标识符设为true 时,正好线程在sleep,会触发sleep内部的一个异常,从而会将线程从sleep中唤醒,但是在sleep抛出异常的同时,它会自动删除刚才设置的 标志位,这将会使 interrupt 这一操作好像没有被执行。

为什么Java会这样设定呢? 因为 Java 是希望当 线程收到 "中断" 信号时,它能自由决定接下来要怎么处理,比如:我们可以在打印报错后 接着写一些代码 :

public class Demo {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            // Thread.currentThread()作用是得到当前的线程
            // isInterrupted() 判断标识符是否为false
            //或者 while(!Thread.interrupted()) 效果一样
           while(!Thread.currentThread().isInterrupted()){
               System.out.println("线程工作中!");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();//打印异常
                   System.out.println("还需要完成的操作...");//2.
                   break;//1.直接退出
               }
           }
        });
        thread.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();//将标识符设置为true
    }
}

 注:

  1. 如果没有sleep,就不会出现上述情况,线程会直接退出!!!
  2. 我们不建议使用 Thread.interrupted() 这种做法,因为该方法是静态方法,意味着所有的线程共用一个标识符,而我们使用的线程肯定不止一个,如果使用该方法,就乱套了!!!

2.5 等待一个线程 - join()

作用:让一个线程等待另一个线程执行结束后,在继续执行。本质上是控制线程结束的顺序。

方法作用
public void join()等待线程结束
public void join(long millis)等待线程结束,但是最多等待 millis 毫秒
public void join(long millis, int nanos)同上,但是精度更高
public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            for (int i = 0; i < 5; i++) {
                System.out.println("线程工作中!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        System.out.println("main线程开始等待");
        thread.join();
        System.out.println("等待结束");
    }
}

 注:

  1. 要分清哪个线程是等待的,哪个线程是被等待的
  2. join() 会出现 "死等" 的情况,我们一般不会使用,建议使用有参数的,可以自定义等待时间

2.6 其他 

方法作用
public static Thread currentThread()返回当前线程对象的引用
public static void sleep(long millis) throws interruptedException当前线程休眠millis毫秒
public static void sleep(long millis, int nanos) throws interruptedException同上,精度更高

三,线程的状态

  •  NEW:  Thread 对象已经有了,start 方法还没有调用
  • TERMINATED:  Thread 对象还在,内核中的线程已经没了
  • RUNNABLE:  就绪状态 (线程已经在 CPU 上运行 / 线程正在排队等待去 CPU 上运行)
  • TIME_WAITING:  阻塞,由于 sleep 这种固定时间的方式产生阻塞
  • WAITING:  阻塞,由于 wait 这种不固定时间的方式产生阻塞
  • BLOCKED:  阻塞,由于锁竞争导致的阻塞
public class Demo2 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        // getState() 获得当前线程的状态
        System.out.println(thread.getState());
        thread.start();
        for (int i = 0; i < 3; i++) {
            System.out.println(thread.getState());
            Thread.sleep(200);
        }
        thread.join();
        System.out.println(thread.getState());
    }
}

 

 

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

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

相关文章

ChatGPT 与前端技术实现制作大屏可视化

像这样的综合案例实分析,我们可以提供案例,维度与指标数据,让ChatGPT与AIGC 帮写出完整代码,并进行一个2行2列的布局设置。 数据与指令如下: 商品名称 销量 目标 完成率 可乐 479 600 79.83% 雪碧 324 600 54.00% 红茶 379 600 63.…

LLMs NLP模型评估Model evaluation ROUGE and BLEU SCORE

在整个课程中&#xff0c;你看到过类似模型在这个任务上表现良好&#xff0c;或者这个微调模型在性能上相对于基础模型有显著提升等陈述。 这些陈述是什么意思&#xff1f;如何形式化你的微调模型在你起初的预训练模型上的性能改进&#xff1f;让我们探讨一些由大型语言模型开…

httpd协议与apache

1.http 相关概念 HTTP是处于应用层的协议&#xff0c;使用TCP传输层协议进行可靠的传送。因此&#xff0c;需要特别提醒的是&#xff0c;万维网是基于因特网的一种广泛因特网应用系统&#xff0c;且万维网采用的是HTTP&#xff08;80/TCP&#xff09;和 HTTPS&#xff08;443/…

哔哩哔哩 B站 bilibili 视频视频音效调节 清澈人声

视频音效调节方式&#xff1a;直接视频播放内容界面内鼠标右键点击视频音效调节 注意&#xff1a;需要使用的是谷歌浏览器&#xff0c;我的火狐浏览器试了不行&#xff0c;都没选项&#xff0c;火狐的出来的界面是这样的&#xff1a; 目录 具体操作如下&#xff1a; 1、谷歌…

第八章,帖子列表

8.1添加帖子列表 <script> import { mapState } from vuex . . . </script> computed: {...mapState([auth,user,articles]) }, <Message :sh

mysql sql 执行流程

监控查询缓存的命中率 show status like ‘%qcache%’; mysql 缓存机制&#xff0c;以及 8.0 为啥取消 select sql_NO_Cache * from 表 where xxx; # 不使用缓存

(WAF)Web应用程序防火墙介绍

&#xff08;WAF&#xff09;Web应用程序防火墙介绍 1. WAF概述 ​ Web应用程序防火墙&#xff08;WAF&#xff09;是一种关键的网络安全解决方案&#xff0c;用于保护Web应用程序免受各种网络攻击和威胁。随着互联网的不断发展&#xff0c;Web应用程序变得越来越复杂&#x…

微服务集成spring cloud sentinel

目录 1. sentinel使用场景 2. sentinel组成 3. sentinel dashboard搭建 4. sentinel客户端详细使用 4.1 引入依赖 4.2 application.properties增加dashboard注册地址 4.3 手动增加限流配置类 4.4 rest接口及service类 4.5 通过dashboard动态配置限流规则 1. sentinel使…

TIM输入捕获笔记 (计算编码电机的频率和占空比)

1. 输入捕获简介 IC (Input Capture) 输入捕获输入捕获模式下&#xff0c;当通道输入引脚出现指定电平跳变时&#xff0c;当前CNT的值将被锁存到CCR中&#xff0c;可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数每个高级定时器和通用定时器都拥有4个输入捕获…

[管理与领导-53]:IT基层管理者 - 8项核心技能 - 8 - 持续改进

前言&#xff1a; 管理者存在的价值就是制定目标&#xff0c;即目标管理、通过团队&#xff08;他人&#xff09;拿到结果。 要想通过他人拿到结果&#xff1a; &#xff08;1&#xff09;目标&#xff1a;制定符合SMART原则的符合业务需求的目标&#xff0c;团队跳一跳就可以…

AUTOSAR规范与ECU软件开发(实践篇)6.7 服务软件组件与应用层软件组件端口连接

在生成了BSW模块的代码后, 切换到ISOLAR-A系统级设计界面,会发现产生一些基础软件模块的服务软件组件: BswM、 ComM、 Det和EcuM等, 如图6.60所示。 图6.60 生成了BSW后的服务软件组件 此时, 如果涉及服务软件组件与应用层软件组件的交互, 就需要为应用层软件组…

数据结构--树4.1

目录 一、树的定义 二、结点的分类 三、结点间的关系 四、结点的层次 五、树的存储结构 一、树的定义 树&#xff08;Tree&#xff09;是n&#xff08;n>0&#xff09;个结点的有限集。当n0时称为空树&#xff0c;在任意一个非空树中&#xff1a; ——有且仅有一个特定的…

2023年高教社杯 国赛数学建模思路 - 复盘:校园消费行为分析

文章目录 0 赛题思路1 赛题背景2 分析目标3 数据说明4 数据预处理5 数据分析5.1 食堂就餐行为分析5.2 学生消费行为分析 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 赛题背景 校园一卡通是集…

Apache StreamPark系列教程第一篇——安装和体验

一、StreamPark介绍 实时即未来,在实时处理流域 Apache Spark 和 Apache Flink 是一个伟大的进步,尤其是Apache Flink被普遍认为是下一代大数据流计算引擎, 我们在使用 Flink & Spark 时发现从编程模型, 启动配置到运维管理都有很多可以抽象共用的地方, 我们将一些好的经验…

02.sqlite3学习——嵌入式数据库的基本要求和SQLite3的安装

目录 嵌入式数据库的基本要求和SQLite3的安装 嵌入式数据库的基本要求 常见嵌入式数据库 sqlite3简介 SQLite3编程接口模型 ubuntu 22.04下的SQLite安装 嵌入式数据库的基本要求和SQLite3的安装 嵌入式数据库的基本要求 常见嵌入式数据库 sqlite3简介 SQLite3编程接口模…

【awd系列】Bugku S3 AWD排位赛-9 pwn类型

文章目录 二进制下载检查分析运行二进制ida分析解题思路exp 二进制下载 下载地址&#xff1a;传送门 检查分析 [rootningan 3rd]# file pwn pwn: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for …

Vue中ElementUI结合transform使用时,发现弹框定位不准确问题

在近期开发中&#xff0c;需要将1920*1080放到更大像素大屏上演示&#xff0c;所以需要使用到transform来对页面进行缩放&#xff0c;但是此时发现弹框定位出错问题&#xff0c;无法准备定位到实际位置。 查看element-ui官方文档无果后&#xff0c;打算更换新的框架进行开发&am…

【业务功能篇85】微服务-springcloud-Nginx-反向代理-网关

Nginx域名 1.hosts文件 在c:/window/system32/drivers/etc/hosts文件&#xff0c;我们在这个文件中添加 192.168.56.100 msb.mall.com注意如果是没有操作权限&#xff0c;那么点击该文件右击属性&#xff0c;去掉只读属性即可 通过这个域名访问到Nginx服务 2.Nginx的方向代…

[牛客复盘] 牛客周赛 Round 9 20230827

[牛客复盘] 牛客周赛 Round 9 20230827 总结小美的外卖订单编号1. 题目描述2. 思路分析3. 代码实现 小美的加法1. 题目描述2. 思路分析3. 代码实现 小美的01串翻转1. 题目描述2. 思路分析3. 代码实现 小美的数组操作1. 题目描述2. 思路分析3. 代码实现 六、参考链接 总结 又是…

Batbot电力云平台在智能配电室中的应用

智能配电室管理系统是物联网应用中的底层应用场景&#xff0c;无论是新基建下的智能升级&#xff0c;还是双碳目标下的能源管理&#xff0c;都离不开智能配电运维对传统配电室的智慧改造。Batbot智慧电力&#xff08;运维&#xff09;云平台通过对配电室关键电力设备部署传感器…