JavaEE语法第二章之多线程(初阶二)

news2024/11/16 5:21:56

目录

一、线程常用方法

1.1启动一个线程-start()

1.2中断一个线程

1.2.1使用自定义的变量来作为标志位.

1.2.2使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定义标志位.

1.2.3观察标志位是否清除

1.3等待一个线程-join()

1.4获取当前线程引用

 1.5休眠当前线程

二、线程的状态

2.1观察线程的所有状态

2.2线程状态和状态转移的意义

2.3观察线程的状态和转移

2.3.1关注 NEW 、RUNNABLE 、TERMINATED 状态的转换 

2.3.2关注 WAITING 、BLOCKED 、TIMED_WAITING 状态的转换


一、线程常用方法

1.1启动一个线程-start()

之前我们已经看到了如何通过覆写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。

  • 覆写 run 方法是提供给线程要做的事情的指令清单
  • 线程对象可以认为是把 李四、王五叫过来了
  • 而调用 start() 方法,就是喊一声:”行动起来!“,线程才真正独立去执行了。

 调用 start 方法, 才真的在操作系统的底层创建出一个线程.

1.2中断一个线程

李四一旦进到工作状态,他就会按照行动指南上的步骤去进行工作,不完成是不会结束的。但有时我们需要增加一些机制,例如老板突然来电话了,说转账的对方是个骗子,需要赶紧停止转账,那张三该如何通知李四停止呢?这就涉及到我们的停止线程的方式了。

目前常见的有以下两种方式:
1. 通过共享的标记来进行沟通
2. 调用 interrupt() 方法来通知

1.2.1使用自定义的变量来作为标志位.

public class ThreadDemo9 {
    //布尔类型成员变量:Lambda表达式进行变量捕获
    //自定义标志位
    public static boolean isQuit = false;
    public static void main(String[] args) {
        Thread thread =new Thread(()->{
           while(!isQuit){
               System.out.println("Hello Thread");
               try{
                   Thread.sleep(1000);
               }
               catch(InterruptedException e){
                   e.printStackTrace();
               }
           }
            System.out.println("Thread线程终止");
        });
        thread.start();
        //在主线程中修改isQuit
        try{
            Thread.sleep(3000);
        }
        catch(InterruptedException e){
            e.printStackTrace();
        }
        isQuit=true;
    }
}

如果将isQuit从成员变量改为局部变量,代码能否正常运行?

不能正常运行。因为变量捕获

1.2.2使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定义标志位.

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

public class ThreadDemo10 {
    public static void main(String[] args) {
        Thread thread=new Thread(()->{
            while(!Thread.currentThread().isInterrupted()){
                //currentThread是获取到当前线程的实例
                //此处currentThread得到的对象是Thread
                //isInterrupted是Thread自带的标志位
                System.out.println("Hello Thread");
                try{
                    Thread.sleep(1000);
                }
                catch(InterruptedException e){
                    e.printStackTrace();
                    //手动让其结束
                    break;
                }
            }
        });
        thread.start();
        try{
            Thread.sleep(3000);
        }
        catch(InterruptedException e){
            e.printStackTrace();
        }
        //把Thread内部的标志位设置为true
        thread.interrupt();
    }
}

thread 收到通知的方式有两种:
1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通知,清除中断标志当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择忽略这个异常, 也可以跳出循环结束线程.

2. 否则,只是内部的一个中断标志被设置,thread 可以通过Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志

1.2.3观察标志位是否清除

标志位是否清除, 就类似于一个开关.
Thread.isInterrupted() 相当于按下开关, 开关自动弹起来了. 这个称为 "清除标志位"
Thread.currentThread().isInterrupted() 相当于按下开关之后, 开关弹不起来, 这个称为
"不清除标志位".

 

使用 Thread.isInterrupted() , 线程中断会清除标志位.

public class ThreadDemo {
    private static class MyRunnable implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.interrupted());
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        thread.start();
        thread.interrupt();
    }
}

true // 只有一开始是 true,后边都是 false,因为标志位被清
false
false
false
false
false
false
false
false
false 

使用 Thread.currentThread().isInterrupted() , 线程中断标记位不会清除

public class ThreadDemo {
    private static class MyRunnable implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().isInterrupted());
            }}
    }
    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        thread.start();
        thread.interrupt();
    }
}

 true // 全部是 true,因为标志位没有被清
true
true
true
true
true
true
true
true
true 

1.3等待一个线程-join()

有时,我们需要等待一个线程完成它的工作后,才能进行自己的下一步工作。例如,张三只有等李四转账成功,才决定是否存钱,这时我们需要一个方法明确等待线程的结束。

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

        try{
            thread.join();
        }
        catch(InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("Hello Main");
    }
}

 

  1.4获取当前线程引用

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

 1.5休眠当前线程

public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
        System.out.println(System.currentTimeMillis());
        Thread.sleep(3 * 1000);
        System.out.println(System.currentTimeMillis());
    }
}

二、线程的状态

2.1观察线程的所有状态

线程的状态是一个枚举类型 Thread.State

public class ThreadState {
    public static void main(String[] args) {
        for (Thread.State state : Thread.State.values()) {
            System.out.println(state);
        }
    }
}
public class ThreadDemo12 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread =new Thread(()->{
           while(true){
                try{
                    Thread.sleep(1000);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
           }
        });
        System.out.println(thread.getState());
        thread.start();
        Thread.sleep(2000);
        System.out.println(thread.getState());

    }
}
  • NEW: 安排了工作, 还未开始行动
  • RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作.
  • BLOCKED: 这几个都表示排队等着其他事情
  • WAITING: 这几个都表示排队等着其他事情
  • TIMED_WAITING: 这几个都表示排队等着其他事情
  • TERMINATED: 工作完成了.

 2.2线程状态和状态转移的意义

 

还是我们之前的例子:
刚把李四、王五找来,还是给他们在安排任务,没让他们行动起来,就是 NEW 状态;
当李四、王五开始去窗口排队,等待服务,就进入到 RUNNABLE 状态。该状态并不表示已经被银行工作人员开始接待,排在队伍中也是属于该状态,即可被服务的状态,是否开始服务,则看调度器的调度;当李四、王五因为一些事情需要去忙,例如需要填写信息、回家取证件、发呆一会等等时,进入BLOCKED 、WATING 、TIMED_WAITING 状态,至于这些状态的细分,我们以后再详解;如果李四、王五已经忙完,为 TERMINATED 状态。所以,之前我们学过的 isAlive() 方法,可以认为是处于不是 NEW 和 TERMINATED 的状态都是活着的。 

2.3观察线程的状态和转移

2.3.1关注 NEW 、RUNNABLE 、TERMINATED 状态的转换 

public class ThreadStateTransfer {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            for (int i = 0; i < 1000_0000; i++) {
            }
        }, "李四");
        System.out.println(t.getName() + ": " + t.getState());;
        t.start();
        while (t.isAlive()) {
            System.out.println(t.getName() + ": " + t.getState());;
        }
        System.out.println(t.getName() + ": " + t.getState());;
    }
}

2.3.2关注 WAITING 、BLOCKED 、TIMED_WAITING 状态的转换

public static void main(String[] args) {
        final Object object = new Object();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (object) {
                    while (true) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();}
                    }
                }
            }
        }, "t1");
        t1.start();
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (object) {
                    System.out.println("hehe");
                }
            }
        }, "t2");
        t2.start();
    }

使用 jconsole 可以看到 t1 的状态是 TIMED_WAITING , t2 的状态是 BLOCKED

修改上面的代码, 把 t1 中的 sleep 换成 wait

public static void main(String[] args) {
        final Object object = new Object();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (object) {
                    try {
// [修改这里就可以了!!!!!]
// Thread.sleep(1000);
                        object.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "t1");
...
    }

使用 jconsole 可以看到 t1 的状态是 WAITING

  • BLOCKED 表示等待获取锁, WAITING 和 TIMED_WAITING 表示等待其他线程发来通知.
  • TIMED_WAITING 线程在等待唤醒,但设置了时限; WAITING 线程在无限等待唤醒

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

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

相关文章

Typora文本的使用

1. 如何创建目录&#xff1f; 输入几个#&#xff0c;再加空格&#xff0c;写入文字回车后就是几级标题&#xff1b; 2. 如何输入代码块&#xff1f; 英文状态下&#xff0c;输入三个反引号&#xff0c;然后回车即可&#xff1b; 3. 如何输入竖线和小圆点&#xff1f; 4. 如何…

SSH远程直连Docker容器

文章目录 1. 下载docker镜像2. 安装ssh服务3. 本地局域网测试4. 安装cpolar5. 配置公网访问地址6. SSH公网远程连接测试7.固定连接公网地址8. SSH固定地址连接测试8. SSH固定地址连接测试 转载自cpolar极点云文章&#xff1a;SSH远程直连Docker容器 在某些特殊需求下,我们想ssh…

使用显式特征的在线交互感知提升网络

目录 1介绍 2相关工作 2.1提升建模 2.2特征交互 3前提 4提出的方法 4.1架构 4.2训练 5试验评估 6结论和未来 英文题目&#xff1a;Explicit Feature Interaction-aware Uplift Network for Online Marketing 翻译&#xff1a;使用显式特征的在线交互感知提升网络 单…

MATLAB 之 Simulink 系统仿真实例和 S 函数的设计与应用

这里写目录标题 一、Simulink 系统仿真实例1. 方法一2. 方法二3. 方法三 二、S 函数的设计与应用1. 用 MATLAB 语言编写 S 函数1.1 主程序1.2 子程序 2. S 函数的应用 一、Simulink 系统仿真实例 下面的应用实例我们将分别采用不同建模方法为系统建模并仿真。例如&#xff0c;…

博客质量分计算——发布 version 5

目录 1. 背景2. 质量分 version 52.1 version 4 存在问题分析2.2 version 5 改进2.3 消融分析2.3.1 正向积极得分消融实验2.3.2 正向累积得分单变量实验2.3.3 非高分文章消融实验 2.4 V4 和 V5 版本质量分分布对比 3. 总结4. 参考 1. 背景 博客质量分顾名思义是用于衡量一篇博…

现代物理工程选讲:辐射探测与测量----射线与物质相互作用

重带电粒子与物质相互作用 与靶物质核外电子发生库伦相互作用电子获得能量脱离原子核的束缚&#xff08;或跃迁到高能级&#xff09;&#xff0c;从而被电离&#xff08;或激发&#xff09;每次碰撞只损失很小一部分能量&#xff08;~1/500)径迹是直线 阻止本领 Stopping Pow…

【Kubernetes资源篇】Secret加密数据配置管理详解

文章目录 一、Secret加密配置理论知识1、Secret是什么?2、Secret和configMap的区别3、Secret的参数和类型 二、实践&#xff1a;使用Secret进行加密1、方式一&#xff1a;环境变量方式引入2、方式二&#xff1a;卷挂载方式引入 一、Secret加密配置理论知识 1、Secret是什么?…

西安石油大学Python期末复习

Python期末复习 一、单选题 1. Python语言属于(C) A.机器语言 B.汇编语言 C.高级语言 D.以上都不是 2.Python 解释器环境中&#xff0c;用于表示上一次运算结果的特殊变量为(B) A. : B. _ C. > D.# 3.为了给整型变量x、y、z赋初值10&#xff0c…

Codeforces Round 868 (Div. 2) F. Random Walk(树上期望)

题目 n(n<2e5)个点的树&#xff0c; 从起点s出发&#xff0c;每次等概率选择一条边&#xff0c;随机游走到相邻点 若走到t&#xff0c;则停止&#xff0c;问每个点经过的期望次数&#xff0c;答案对998244353取模 思路来源 DLUT_Zeratul讲解 题解 需要分成三部分考虑…

Spring面试题--Spring中的循环引用(循环依赖)

我们以上述代码为例分析一下死循环产生的过程 为什么A是半成品呢&#xff1f; 如果熟悉bean的生命周期&#xff0c;那么在实例化对象A的时候&#xff0c;首先去调用的是构造函数&#xff0c;像是依赖注入还有接口的实现重写什么的&#xff0c;还有后置处理器&#xff0c;初始化…

【笔记】微机原理及接口技术3 -- 中断技术与DMA控制器

目录 中断技术中断概述中断处理过程 可编程定时器与计数器DMA 控制器8237A 结构工作方式工作时序 中断技术 中断概述 中断的流程是&#xff1f; CPU 正在执行进程 A此时外部或者内部中断请求发生&#xff0c;CPU 响应中断进程 A 暂时中断执行&#xff0c;转而运行中断服务程序…

华为OD机试真题 Python 实现【核酸检测人员安排】【2023Q1 100分】,附详细解题思路

目录 一、题目描述二、输入描述三、输出描述四、补充说明五、Python算法源码六、效果展示1、输入2、输出 一、题目描述 在系统、网络均正常的情况下组织核酸采样员和志愿者对人群进行核酸检测筛查。 每名采样员的效率不同&#xff0c;采样效率为N人/小时。 由于外界变化&…

本地springboot项目上传到gitee

1.在gitee上新建一个仓库&#xff1a; 创建后可以拿到仓库地址&#xff1a;https://gitee.com/ouyangshuiming/linux_test.git 2. 选中 创建git仓库 3. 4.最后一步&#xff1a; 一定记得这里要写上一段话&#xff0c;才能成功提交&#xff1a;比如git 提交远程库 最后刷新…

MySQL的Join

1.Join用法 Join连接两张表,大致分为内连接,外连接,右连接,左连接,自然连接。 内连接又叫等值连接,此时的inner可以省略。 USING语句 MySQL中连接SQL语句中,ON子句的语法格式为:table1.column_name = table2.column_name。当模式设计对联接表的列采用了相同的命名样…

React hooks文档笔记(四) useRef

useRef 当想让组件记住一些信息&#xff0c;又不想触发新的渲染&#xff0c;可以使用ref&#xff1a;总是返回同一个对象。 1. state 和 refs 的比较 refs&#xff08;普通的 JavaScript 对象&#xff09; state 更改时不触发重新渲染 更改时触发重新渲染 可变的——修改/…

复现基于unet的眼底血管的医学图像分割项目

代码及数据集&#xff1a; MedicalImageSegmentation: 复现一个医学图像分割的项目 - Gitee.com xin麒/MedicalImageSegmentation - 码云 - 开源中国 (gitee.com) 两个都可以&#xff0c;差不多的&#xff08;要不就使用第二个吧&#xff0c;第二个后续都会继续更新&#xf…

【JUC-1】java多线程线程基础知识

线程创建方式 继承Thread类.实现Runable接口.实现Callable接口. Runable/Callable接口的实现, 都是重写其中的run/call方法, 实现任务逻辑, 再由线程执行器(可以是Thread类,也可以是线程池)并发执行run/call的逻辑. 而Thread类中的包含start方法, 可以控制线程启动,执行任务…

关于最小生成树

最小生成树问题&#xff0c;常用于将所有顶点连通的最大最小代价。比如十个城市去修路&#xff0c;不同成熟时之间修路的代价不同&#xff0c;让你找一个方案可以满足每个城市之间互相连通并且代价最小。 解决这个问题有两个算法&#xff0c;Prim算法和Kruskal算法。不同的是&a…

安装和配置nginx(含https)

文章目录 安装Nginx配置单独的配置&#xff1a;https配置 nginx为什么可以处理高并发 安装Nginx sudo yum update sudo yum install epel-release sudo yum install nginx sudo systemctl start nginx安装好后可以打开自己的域名 看一下默认的页面 配置 具体参考Link 位置 …

香港大学推出创新科技教育基金,拟支持Web3和生成式AI等领域教学

区块链技术是近年来备受关注的领域之一,其应用范围已经涵盖了金融、医疗、物流等众多行业。而随着区块链技术的不断发展和完善&#xff0c;越来越多的企业和机构开始将其应用到实际生产和业务中。作为其中一个重要的应用领域&#xff0c;金融领域也成为了区块链技术的重要应用场…