线程的状态 and 线程安全

news/2024/10/22 13:40:59/

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

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

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

该段代码的运行结果为:

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

public class Main1 {public static void main(String[] args) throws InterruptedException {Thread t=new Thread(()->{System.out.println("hello");});//在启动之前,获取线程状态----》newSystem.out.println(t.getState());//NEWt.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");}});//在启动之前,获取线程状态----》newSystem.out.println(t.getState());//NEWt.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();}}});//在启动之前,获取线程状态----》newSystem.out.println(t.getState());//NEWt.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次//线程1Thread t1=new Thread(()->{for (int i = 0; i < 50000; i++) {counter.add();}});//线程2Thread 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.ppmy.cn/news/1099093.html

相关文章

003微信小程序云开发API数据库-新增集合-删除集合-获取集合信息

文章目录 1.微信小程序云开发API数据库-新增集合案例代码 2.微信小程序云开发API数据库-删除集合案例代码 3.微信小程序云开发API数据库-获取集合信息案例代码 1.微信小程序云开发API数据库-新增集合 微信小程序云开发API数据库是一个方便快捷的数据库解决方案&#xff0c;可以…

【漏洞复现】Tenda路由器存在密码泄露

漏洞描述 腾达W15E路由器外置4根增强型360全向天线&#xff0c;苛刻调校到0.01毫米级的零干扰间距&#xff0c;科学独立布局的信号放大器PA&#xff0c;穿墙性能更强劲&#xff0c;覆盖范围更广&#xff0c;在哪都有好信号。 该型号的路由器系统存在密码泄露漏洞&#xff0c;…

python3 简易 http server:实现本地与远程服务器传大文件

在个人目录下创建新文件httpserver.py &#xff1a; vim httpserver.py文件内容为python3代码&#xff1a; # !/usr/bin/env python3 import datetime import email import html import http.server import io import mimetypes import os import posixpath import re import…

通过 http-server 运行刚打包出来的脚手架项目

这里 我打包了自己的vue项目 react其实也一样 如果我直接 打开打包出来的 dist 下面的index.html 会出现白屏资源找不到 或者跨域等问题 这个问题其实配个nginx也能解决 但是其实如果只是想做个测试 nginx就太麻烦了 我们可以通过npm指令 全局安装一个http-server 终端执行 …

PHP对接阿里云虚拟号的实现(号码隐私保护)

fastadmin 封装框架 实现功能&#xff1a;AXN隐私号绑定、解绑&#xff1b; 场景&#xff1a;为店铺手机号开通虚拟号&#xff0c;用户联系店铺展示虚拟号码&#xff1b; 官方开放文档地址&#xff1a;https://help.aliyun.com/document_detail/59655.html?spma2c4g.111742…

弘玑RPA进阶攻略

弘玑RPA进阶攻略 01.弘玑RPA产品概要02.设计器的安装与卸载03.设计器特性与使用04.工程模式与发布05.变量06.字符串处理07.数组处理08.日期与时间09.数据表格10.对象处理11.逻辑组件12.界面自动化13.界面自动化抓取网页表格数据14.Excel使用15.执行器概览16.中控概览17.语法糖1…

15 轮转数组

轮转数组 题解1 环状替换&#xff08;学习思想&#xff09;&#xff08;空间O(1)&#xff09;题解2 翻转数组&#xff08;有意思好理解&#xff09;&#xff08;空间O(1)&#xff09;题解3 空间O(N)秒答 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&a…

Selling a Menagerie(cf)

该题考察了拓扑排序dfs 题意&#xff1a;你是一个动物园的主人&#xff0c;该动物园由编号从1到n的n只动物组成。然而&#xff0c;维护动物园是相当昂贵的&#xff0c;所以你决定卖掉它&#xff01;众所周知&#xff0c;每种动物都害怕另一种动物。更确切地说&#xff0c;动物…