多线程-线程状态和线程安全(加锁-synchronized 关键字)

news2025/1/16 5:50:07

目录

1.线程状态

 示例:

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

2.线程安全

2.1观察线程不安全

2.2线程不安全的原因

3.synchronized 关键字 - 监视器锁 monitor lock

3.1synchronized 的特性

1. 互斥

2.可重⼊

 应用示例:

3.2synchronized 使⽤⽰例  

1. 修饰代码块: 明确指定锁哪个对象.

2.直接修饰普通⽅法: 锁的 SynchronizedDemo 对象

3.修饰静态⽅法: 锁的 SynchronizedDemo 类的对象


1.线程状态

      在Java中,线程有几种不同的状态,可以通过Thread类的getState()方法获取线程的当前状态。

      线程的状态是⼀个枚举类型 Thread.State
public class ThreadState {
 public static void main(String[] args) {
 for (Thread.State state : Thread.State.values()) {
 System.out.println(state);
         }
     }
}
  1. NEW(新建):新创建的线程尚未启动。
  2. RUNNABLE(可运行):正在Java虚拟机中执行的线程,可能正在执行,也可能正在等待CPU时间片。
  3. BLOCKED(阻塞):被阻塞并等待监视器锁定的线程。当线程试图进入一个同步代码块,而该块已经被其他线程持有时,该线程将进入阻塞状态。
  4. WAITING(等待):无限期等待另一个线程执行特定操作的线程。线程可以通过调用Object类的wait()方法、Thread类的join()方法或LockSupport类的park()方法进入等待状态。
  5. TIMED_WAITING(计时等待):在等待一段时间后自动恢复运行的线程。线程可以通过调用Thread类的sleep()方法、Object类的wait方法、Thread类的join方法进入计时等待状态。
  6. TERMINATED(终止):已经执行完毕的线程,不再运行。

 示例:

我们用getState()来获取线程的状态。

package 多线程;

public class ThreadDemo13 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            for (int i = 0; i < 5; i++) {
                System.out.println("线程运行中");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        //启动之前状态是new状态
        System.out.println(t.getState());
        t.start();
        System.out.println(t.getState());
        t.join();
        System.out.println(t.getState());
        System.out.println("t线程结束");
    }
}

       我们查看结果一开始线程的状态是NEW,当我们t.start后线程的状态变成了RUNNABLE,之后线程开始运行。我们使用t.join()提前结束线程。线程状态改变成了TERMINTED。

 

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

 

2.线程安全

        线程安全是指在多线程环境下,多个线程同时访问共享资源时,不会出现数据不一致、竞态条件和死锁等问题。在并发编程中,如果多个线程同时访问共享的可变数据,可能会导致数据不一致的情况。例如,一个线程在读取一个共享变量的同时,另一个线程正在修改该变量,这就可能导致读取到的数据是脏数据(脏数据是指在并发环境下,一个线程正在修改某个共享变量的同时,另一个线程正在读取同一个变量的值,从而导致读取到的值不正确或者不符合预期。这种情况也被称为“读写冲突”。)或者不符合预期的结果。为了保证线程安全,需要采取相应的措施来避免这类问题。

2.1观察线程不安全

我们写一个程序来观察

// 此处定义⼀个 int 类型的变量
private static int count = 0;
public static void main(String[] args) throws InterruptedException {
 Thread t1 = new Thread(() -> {
// 对 count 变量进⾏⾃增 5w 次
 for (int i = 0; i < 50000; i++) {
 count++;
 }
 });
 Thread t2 = new Thread(() -> {
 // 对 count 变量进⾏⾃增 5w 次
 for (int i = 0; i < 50000; i++) {
 count++;
 }
 });
 t1.start();
 t2.start();
 // 如果没有这俩 join, 肯定不⾏的. 线程还没⾃增完, 就开始打印了. 很可能打印出来的 cou
 t1.join();
 t2.join();
 // 预期结果应该是 10w
 System.out.println("count: " + count);
}

       我们运行结果会发现每次运行的结果都是不一样的,这就是因为线程不安全所以我们的结果不正确。上⾯的线程不安全的代码中, 涉及到多个线程针对 count 变量进⾏修改. 此时这个 count 是⼀个多个线程都能访问到的 "共享数据"

2.2线程不安全的原因

1.根本原因:操作系统上的线程是“抢占式执行”“随机调度”=>线程之间执行的顺序带来了很多变数

2.代码结构:代码中多个线程,同时修改同一个变量

一个线程修改一个变量,没事

多个线程读取同一个变量,没事

多个线程修改不同变量,没事

3.直接原因:上述多线程修改操作,本身不是“原子的”(原子性是指一个操作是不可中断的,在执行过程中不能被其他线程或事件打断,要么全部执行成功,要么全部不执行。如果一个操作具有原子性,那么多个线程同时执行这个操作时,不会出现数据不一致的问题。)

3.synchronized 关键字 - 监视器锁 monitor lock

         synchronized是Java中用于实现同步的关键字,可以将代码块或方法声明为同步代码块或同步方法。在多线程环境下,使用synchronized可以确保同一时间只有一个线程能够访问共享资源,从而避免数据不一致的问题。

3.1synchronized 的特性

1. 互斥

        synchronized 会起到互斥效果, 某个线程执⾏到某个对象的 synchronized 中时, 其他线程如果也执⾏到同⼀个对象 synchronized 就会阻塞等待.
进⼊ synchronized 修饰的代码块, 相当于 加锁
退出 synchronized 修饰的代码块, 相当于 解锁

2.可重⼊

         synchronized 同步块对同⼀条线程来说是可重⼊的,不会出现⾃⼰把⾃⼰锁死的问题;

 应用示例:

我们对count进行加锁

package 多线程;

public class ThreadDemo14 {
    private static int count = 0;

    public static void main(String[] args) throws InterruptedException {
        //创建一个对象
        Object locker = new Object();

        Thread t1 = new Thread(()->{
            for (int i = 0; i < 5000; i++) {
                synchronized (locker) {//进程如{}就会加锁
                    count++;
                }//出了{}就会解锁
            }
        });
        Thread t2 = new Thread(()->{
            for (int i = 0; i < 5000; i++) {
                synchronized (locker) {
                    count++;
                }
            }
        });
        t1.start();
        t2.start();
        // 如果没有这俩 join, 肯定不⾏的. 线程还没⾃增完, 就开始打印了. 
        t1.join();
        t2.join();
        // 预期结果应该是 10w
        System.out.println("count: " + count);
    }

 这样我们的结果就正确了。

3.2synchronized 使⽤⽰例  

1. 修饰代码块: 明确指定锁哪个对象.

锁任意对象
public class SynchronizedDemo {
 private Object locker = new Object();
 
 public void method() {
 synchronized (locker) {
 
      }
   }
}
锁当前对象
public class SynchronizedDemo {
 public void method() {
 synchronized (this) {
 
      }
   }
}

2.直接修饰普通⽅法: 锁的 SynchronizedDemo 对象

public class SynchronizedDemo {
 public synchronized void methond() {
     }
}

3.修饰静态⽅法: 锁的 SynchronizedDemo 类的对象

public class SynchronizedDemo {
 public synchronized static void method() {
    }
}

                                                                   希望大家多多支持!

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

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

相关文章

简单了解AJAX

文章目录 1、什么是AJAX2、AJAX快速入门3、Axios异步框架3.1、Axios 快速入门3.2、Axios 请求方式别名 1、什么是AJAX 概念&#xff1a;AJAX(Asynchronous JavaScript And XML)&#xff1a;异步的 JavaScript 和 XML AJAX作用&#xff1a; 与服务器进行数据交换&#xff1a;通…

【Unity学习笔记】New Input System 部分源码和测试用例补充

转载请注明出处&#xff1a;&#x1f517;https://blog.csdn.net/weixin_44013533/article/details/135630016 作者&#xff1a;CSDN|Ringleader| 主要参考&#xff1a; Unity官方Input System手册与API【Unity学习笔记】Unity TestRunner使用【Unity学习笔记】第十二 New Inp…

k8s资源介绍

Kubernetes架构图 Kubernetes系统用于管理分布式节点集群中的微服务或容器化应用程序&#xff0c;并且其提供了零停机时间部署、自动回滚、缩放和容器的自愈&#xff08;其中包括自动配置、自动重启、自动复制的高弹性基础设施&#xff0c;以及容器的自动缩放等&#xff09;等…

java黑马学习笔记

数组 变量存在栈中&#xff0c;变量值存放在堆中。 数组反转 public class test{public static void main(String[] args){//目标&#xff1a;完成数组反转int[] arr {10,20,30,40,50};for (int i 0,j arr.length - 1;i < j;i,j--){int tep arr[j]; //后一个值赋给临时…

数学建模常见算法的通俗理解(2)

目录 6 K-Means&#xff08;K-均值&#xff09;聚类算法&#xff08;无需分割数据即可分类&#xff09; 6.1 粗浅理解 6.2 算法过程 6.2.1 选定质心 6.2.2 分配点 6.2.3 评价 7 KNN算法&#xff08;K近邻算法&#xff09;&#xff08;K个最近的决定方案&#xff09; 7.…

怎么从视频中提取动图?一个方法快速提取gif

视频以连续的方式播放一系列图像帧&#xff0c;通过每秒播放的帧数&#xff08;帧率&#xff09;来创做&#xff0c;由于GIF动图则以循环播放一系列静态图像帧的方式展现动画效果。由于视频的优势在于流畅的动画、丰富的细节和长时间播放&#xff0c;因此常用于电影、电视节目、…

DAG最小路径点覆盖,最小路径可重复覆盖,详解

文章目录 前言有向无环图的最小路径点覆盖概念拆点二分图定理**证明** 最小路径可重复覆盖解决策略代码实现 OJ练习 前言 关于二分图&#xff1a;二分图及染色法判定 关于二分图最大匹配&#xff1a;二分图最大匹配——匈牙利算法详解 关于二分图带权最大完备匹配&#xff1…

Docker使用及部署python项目

一、准备项目 ​ 我写的是一个爬取某ppt网站的代码&#xff0c;就一个ppt1.py是爬虫&#xff0c;然后&#xff0c;ppts是存放下载的ppt的 二、准备requirement.txt文件 这个是需要哪些python库支持&#xff0c;写好 ​ 三、准备Dockerfile文件 需要一个名为Dockerfile的文件&…

基于SpringBoot的船运物流管理系统

文章目录 项目介绍主要功能部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &#x1f345;文末获取…

计算机组成原理04:一位乘法

原码的一位乘法是基于加法设计的。回想我们在竖式计算乘法时&#xff0c;都是通过一个数与另外一个数的另外一位相乘&#xff0c;最后相加得到结果。计算机计算原码一位乘法也是一样的原理。这里就涉及到计算时一个非常重要的操作&#xff1a;数据移位。 原码乘法问题分析 需…

13.浮动面板(PaletteSet)

愿你出走半生,归来仍是少年&#xff01; 环境&#xff1a;.NET FrameWork4.5、ObjectArx 2016 64bit、Entity Framework 6. 在CAD中进行通用组件开发或常驻界面的控件开发时&#xff0c;可使用PaletteSet作为停靠面板&#xff0c;然后将自己的空间放入其中。 1.示例 SearchRe…

React初探:从环境搭建到Hooks应用全解析

React初探&#xff1a;从环境搭建到Hooks应用全解析 一、React介绍 1、React是什么 React是由Facebook开发的一款用于构建用户界面的JavaScript库。它主要用于构建单页面应用中的UI组件&#xff0c;通过组件化的方式让开发者能够更轻松地构建可维护且高效的用户界面。 Reac…

初始RabbitMQ(入门篇)

消息队列(MQ) 本质上就是一个队列,一个先进先出的队列,队列中存放的内容是message(消息),是一种跨进程的通信机制,用于上下游传递消息, 为什么使用MQ: 削峰填谷: MQ可以很好的做一个缓冲机制,例如在一个系统中有A和B两个应用,A是接收用户的请求的,然后A调用B进行处理. 这时…

前端基础面试题大全

一、Vue 文章目录 一、Vue1、vue 修改数据页面不重新渲染**数组/对象的响应式 &#xff0c;vue 里面是怎么处理的&#xff1f;** 2、生命周期Vue 生命周期都有哪些&#xff1f;父子组件生命周期执行顺序 3、watch 和 computed 的区别4、组件通信&#xff08;组件间传值&#xf…

gin中间件篇

1. 全局中间件 所有请求都经过此中间件 package mainimport ("fmt""time""github.com/gin-gonic/gin" )// 定义中间 func MiddleWare() gin.HandlerFunc {return func(c *gin.Context) {t : time.Now()fmt.Println("中间件开始执行了&quo…

力扣每日一题---1547. 切棍子的最小成本

//当我们将棍子分段之后&#xff0c;我们是不是想到了怎么组合这些棍子 //并且这些棍子有一个性质就是只能与相邻的进行组合 //暴力搜索的话复杂度很高 //在思考暴力搜索的时候&#xff0c;我们发现一个规律 //比如棍子长度1 2 1 1 2 //那么与最后一个2组合的棍子有&#xff0c…

Vue3+ElementUIPlus颜色选择器,Ruoyi框架动态替换图片

需求为&#xff0c;需要动态的替换头部和底部图片的颜色&#xff0c;通过固定的颜色 要实现可以动态的通过颜色&#xff0c;去替换的效果。 一、通过将选择的颜色&#xff0c;通过Vuex来进行一个存储&#xff0c;用户后续的使用 <el-form-item label"顶部底部背景&quo…

LabVIEW滚动轴承故障在线监测

展示了如何将LabVIEW开发出一种有效的滚动轴承故障在线监测系统。介绍了该系统的开发过程、工作原理及其在实际应用中的效果。该系统成功地应用于对滚动轴承故障的早期诊断&#xff0c;提高了故障检测的准确性和效率。 滚动轴承在工作过程中会产生复杂的振动信号&#xff0c;包…

19. JDK8以后的时间类(Date类、日期格式化类、日历类、工具类)

JDK8以后的时间类 Date类1. ZoneID类1.1 方法1.2 代码示例 2. Instant类2.1 方法2.2 代码示例 3. ZoneDateTime类3.1 方法3.2 代码示例 日期格式化类1. DateTimeFormatter类1.1 方法1.2 代码示例 日历类1. LocalDate类1.1 方法1.2 代码示例 2. LocalTime类2.1 方法2.2 代码示例…

Java设计模式详解-更新中

收藏和关注的同时&#xff0c;请也关注 公众号 “IT技术馆” 各位大家好&#xff0c;从今天开始&#xff0c;作者开始整理 《JAVA软件设计模式&#xff08;GOF&#xff09;》 专栏。请各位多多关注&#xff01; 该专栏是根据作者的技术经验和设计模式的了解&#xff0c;进行详…