线程的状态 and 线程安全

news2024/10/13 0:30:59

在操作系统中的线程,自身是有一个状态的~,但是Java Thread是对系统线程的封装,把这里的状态又进一步精细化了。

1.NEW 系统中的线程还没创建出来呢!只是有一个Thread对象~

public class Main1 {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            System.out.println("hello");
        });
        
        //在启动之前,获取线程状态----》new
        System.out.println(t.getState());//NEW
        
        t.start();
    }
}

该段代码的运行结果为:

2.TERMINATED:系统中的线程已经结束了,Thread对象还在~

public class Main1 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            System.out.println("hello");
        });

        //在启动之前,获取线程状态----》new
        System.out.println(t.getState());//NEW

        t.start();

        Thread.sleep(1000);
        System.out.println(t.getState());//TERMINATED

    }
}

该段代码的运行结果为:

3.RUNNABLE就绪状态:

  • 正在CPU上运行
  • 准备好随时可以去CPU运行

跟上述的代码差不多,只不过用了while()循环

public class Main1 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            while (true){
                System.out.println("hello");
            }
        });

        //在启动之前,获取线程状态----》new
        System.out.println(t.getState());//NEW

        t.start();

        Thread.sleep(1000);
        System.out.println(t.getState());//TERMINATED

    }
}

该段代码的运行结果为:

4.TIMED_WAITING指定时间等待:如sleep()方法

public class Main1 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            while (true){
                System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        //在启动之前,获取线程状态----》new
        System.out.println(t.getState());//NEW

        t.start();

        Thread.sleep(1000);
        System.out.println(t.getState());//TERMINATED

    }
}

5.BLOCKED:表示等待锁将出现的状态

6.WAITING:使用wait()方法出现的状态

一条主线,三个支线

理解线程的状态:意义就算让我们能够更好的进行多线程代码的调试~


多线程带来的风险——》线程安全?(重点难点考点)

多线程不安全是指:某个代码再多线程环境下执行,会出bug!

本质上是因为:多线程的各线程的调度顺序是不确定的~

我们来看一下下述代码:两个线程同时对一个变量各自自增5W次(线程不安全)

class Counter{
    private int count=0;
    
    public void add(){
        count++;
    }
    
    public int get(){
        return count;
    }
}
public class Main2 {
    public static void main(String[] args) throws InterruptedException{
        Counter counter=new Counter();
        
        //搞两个线程,两个线程分别对这个count自增5W次
        //线程1
        Thread t1=new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                counter.add();
            }
        });
        
        //线程2
        Thread t2=new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                counter.add();
            }
        });
        
        //启动线程
        t1.start();
        t2.start();
        
        //等待两个线程执行结束,然后看一下结果
        t1.join();
        t2.join();

        System.out.println(counter.get());
        //预期结果是10W,但是,实际结果像是一个随机值,每次执行的结果都不一样
    }
}

在上述代码中,两个线程分别对count自增5W次,预期结果是10W,但是,实际结果像是一个随机值,每次执行的结果都不一样,下面的运行结果是笔者截自五次的运行,那么,我们来看一下:

经过上述的运行结果,我们可以得出:实际结果与预期结果不一样:就是Bug,这就是由多线程引起的Bug——》线程不安全/线程安全问题。

那么,我们来思考一下:为啥会出现count随机值的问题呢??

主要是和:线程相关的调度随机性密切相关!

上述代码中:count++操作,本质上是三个CPU指令构成的~:

  1. load把内存中的数据读取到CPU寄存器中
  2. add就算把寄存器中的值进行+1运算
  3. save把寄存器中的值写回到内存中

说白了,归根结底,线程安全问题:全是因为线程的无序调度导致了执行顺序的不确定,从而结果就发生变化了!(罪魁祸首,万恶之源)

那么,线程不安全的原因又有哪些呢??

  1. 抢占式执行(罪魁祸首,万恶之源)
  2. 多线程修改同一个变量:一个线程修改同一个变量——》安全;多个线程读取同一个变量——》安全;多个线程修改不同变量——》安全
  3. 修改操作:不是原子的(原子:不可分割的最小单位称为原子)。如上述的count++操作,就不是原子的,里面可以分为三个操作:load,add,save,因此,某个操作对应单个CPU指令就是原子的,如果这个操作对应多个CPU指令,大概率就不是原子的!正是因为不少原子的,导致两个线程的指令排列存在更多变数了!(如果直接使用=(等号)进行赋值,就是一个原子的操作(count=4)
  4. 内存可见性引起的线程不安全,另外的场景会引起这样的问题,和当前count++列子无关
  5. 指令重排序引起的线程不安全,另外的场景会引起这样的问题,和当前count++列子无关

如何解决线程不安全问题呢??这就得从原因入手了~~

如果用join()来防止线程的抢占式执行,那么,还要多线程干啥??直接一个线程串行执行呗!(多线程的初心:进行并发编程,更好的利用多核CPU)

思考:能否让count++变成原子的呢??当然有办法——》加锁!!

锁的核心操作有两个,1.加锁,2.解锁

一旦某个线程加锁了之后,其他线程也想加锁,就不能直接加上,就需要阻塞等待,一直等到拿到锁的线程释放了锁为止!!

记住:线程调度的方式是:抢占式执行!!

由于抢占式执行,导致了线程之间的调度是随机的!!当1号滑稽释放锁之后,等待锁的2号滑稽和3号滑稽谁能抢先一步拿到锁,成功加锁是不确定的!~

本文关于:线程的状态 and 线程安全大致到此结束,若是对Java中如何进行加锁的,感兴趣,那么,请参考下篇文章~~

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

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

相关文章

日入千元什么感觉?信息安全就是这么“吸金”!

一年一次的护网行动已经火热开始了&#xff0c;大家还记得前段时间给大家推荐的护网吗&#xff1f; 现在不管是国家还是企业都很重视信息安全&#xff0c;毕竟科技的发展越来越迅速&#xff0c;我们的信息安全时时刻刻都需要保障。 据研究机构统计&#xff0c;截止2021年&…

数字出版的资源管理系统软件开发

出版行业资源管理系统是为出版公司和数字出版机构设计的软件工具&#xff0c;用于帮助管理和优化出版过程。这些系统通常具有多种功能&#xff0c;以支持从内容创作到分销的各个方面。以下是出版行业资源管理系统的一些主要功能&#xff0c;希望对大家有所帮助。北京木奇移动技…

【计算机基础知识2】操作系统、应用程序和编程语言

目录 前言 一、计算机操作系统 二、计算机应用程序 三、计算机编程语言 四、操作系统、应用程序和编程语言的相互关系 总结 前言 计算机的操作系统、应用程序和编程语言是计算机科学中非常重要的三个方面。了解这三个方面的基础知识和它们之间的相互关系&#xff0c;对于…

编程技巧,Python缩进规则(包含快捷键)

和其它程序设计语言​ &#xff08;如 Java、C 语言&#xff09;采用大括号“{}”分隔代码块不同&#xff0c;Python 采用代码缩进和冒号&#xff08; : &#xff09;来区分代码块之间的层次。 ​ 在 Python 中&#xff0c;对于类定义、函数定义、流程控制语句、异常处理语句等…

lvs负载均衡、LVS集群部署

四&#xff1a;LVS集群部署 lvs给nginx做负载均衡项目 218lvs&#xff08;DR 负载均衡器&#xff09; yum -y install ipvsadm&#xff08;安装这个工具来管理lvs&#xff09; 设置VIP192.168.142.120 创建ipvsadm的文件用来存放lvs的规则 定义策略 ipvsadm -C //清空现有…

如何使用element-ui相关组件如:el-select,el-table,el-switch,el-pagination,el-dialog

element-ui 官方链接&#xff1a; 组件 | Elementhttps://element.eleme.cn/#/zh-CN/component/installation el-select <!-- 用户类型选择框<template> 看情况使用value选择框绑定的值 命名必须是value不能改v-for"item in Options" options数据源来自于…

【dubbo3】看懂消费者如何发现提供者

服务发现机制 服务发现是RPC框架非常重要的能力。典型的服务发现一般有两种&#xff1a;接口级服务发现、应用级服务发现。  接口级服务发现典型代表是dubbo2基于zk的服务发现机制。提供者直接向注册中心注册接口信息及地址&#xff0c;消费者通过接口从注册中心拿到对应的地址…

1 Linux输入子系统

1 Linux输入子系统 https://www.cnblogs.com/beijiqie1104/p/11418082.html Linux input 子系统详解 https://www.cnblogs.com/yikoulinux/p/15208238.html

2023-9-8 求组合数(四)

题目链接&#xff1a;求组合数 IV #include <iostream> #include <algorithm>using namespace std;const int N 5010;int primes[N], cnt; bool st[N]; // 每个质数的次数 int sum[N];void get_primes(int n) {for(int i 2; i < n; i){if(!st[i]) primes[cnt]…

5.删除链表元素问题

1.删除特点节点 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5]示例 2&#xff1a; 输…

【LeetCode: 207.课程表:拓扑排序+图】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

【C/C++】BMP格式32位转24位

问题 如题 解决方法 bmp文件格式参考:【C/C++】BITMAP格式分析_vc++ bitmap头文件_sunriver2000的博客-CSDN博客BITMAP文件大体上分成四个部分,如下表所示。文件部分长度(字节)位图文件头 Bitmap File Header14位图信息数据头 Bitmap Info Header40调色板 Palette4*n (n≥…

Linux 安装elasticsearch-7.5.1

相关链接 官⽹&#xff1a; https://www.elastic.co/cn/downloads/elasticsearch 下载&#xff1a; wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.5.1-linux-x86_64.tar.gz 分词器&#xff1a; https://github.com/medcl/elasticsearch-an…

MJDK 如何实现压缩速率的 5 倍提升?

MJDK 是基于 OpenJDK 构建的美团 JDK 发行版。本文主要介绍 MJDK 是如何在保障 java.util.zip.* API 及压缩格式兼容性的前提下&#xff0c;实现压缩/解压缩速率提升 5-10 倍的效果。希望相关的经验能够帮助到更多的技术同学。 1 前言 数据压缩技术[1]因可有效降低数据存储及…

appium环境搭建

一.appium环境搭建 1.python3 python3的下载安装这里就不多做介绍了&#xff0c;当然你也可以选择自己喜欢的语音&#xff0c;比如java… 2.jdk 1&#xff09;下载地址 官网(需登录账号)&#xff1a; https://www.oracle.com/java/technologies/downloads/ 百度网盘&…

2022护网行动经验分享(2023护网招人)

今年的护网又开始摇人了&#xff0c;不知道大家有想法没&#xff1f; 去年的护网结束之后&#xff0c;朋友圈感觉是在过年&#xff0c;到处是倒计时和庆祝声。 看得出来防守方们7*24小时的看监控还是比较无奈的。 本次复盘基于我对整个护网行动的观察总结而来&#xff0c;仅…

Spring Security OAuth2 远程命令执行漏洞

文章目录 一、搭建环境二、漏洞验证三、准备payload四、执行payload五、变形payload 一、搭建环境 cd vulhub/spring/CVE-2016-4977/ docker-compose up -d 二、漏洞验证 访问 http://192.168.10.171:8080/oauth/authorize?response_type${233*233}&client_idacme&s…

早期传言和升级:Apple Watch Ultra 2,我们的期待!

Apple Watch Ultra 2可能正在研制中,为去年的Apple Watch Ultras带来升级。现在,该公司提供了一款适合跑步者和户外运动爱好者的智能手表,我们迫切希望看到第二代型号将如何改进。 作为Apple Watch Series 8和Apple Watch SE(2022)的替代品,Apple Watch Ultra具有所有苹…

MPP 与 SMP 的区别,终于有人讲明白了【文末送书】

文章目录 导读01 SMP1. SMP 的典型特征2. SMP的优缺点 02 分布式MPP计算架构1. MPP 架构核心原理2. MPP 典型特征3. MPP优缺点 写作末尾 导读 当今数据计算领域主要的应用程序和模型可大致分为在线事务处理&#xff08;On-line Transaction Processing &#xff0c;OLTP&#…

笔试记录-扔鸡蛋问题

写目录 一个鸡蛋两个鸡蛋K个鸡蛋 今天面试官问了我这个扔鸡蛋问题&#xff0c;以前学过&#xff0c;但是面试的时候想不起来了&#xff0c;应该是直接寄了&#xff0c;接下来总结一下这个问题的动态规划做法. 问题&#xff1a;有一个N层高的楼&#xff0c;现在给你若干个鸡蛋&a…