多线程、进程、线程五种状态、synchronized、volatile、Lock、CAS、死锁、ThreadLocal

1、并发编程

并发编程三要素

  • 原子性:只一个操作要么全部成功,要么全部失败
  • 可见性:一个线程对共享变量的修改,其他线程能够立刻看到
  • 有序性:程序执行的顺序按照代码的先后顺序执行

synchronized,Lock解决原子性问题
volatile,,Lock解决可见性和有序性问题

2、线程和进程的区别

  • 根本区别:进程是操作系统资源分配的最小单位;线程是处理任务调度和执行的最小单位
  • 资源开销:每个进程都有单位的空间,进程间的切换有较大的开销;线程是轻量级的进程,同一类线程共享数据空间,每个线程有独立的运行栈和程序计数器,线程之间的切换开销较小
  • 包含关系:进程包含线程
  • 内存分配:线程共享地址空间和资源,进程之间的地址空间和资源相互独立
  • 影响关系:一个进程崩溃,在保护模式下其他进程不受影响;一个线程崩溃,其他线程也会受影响,整个进程都会崩溃。多进程要比多线程更加健壮
  • 执行关系:进程有独立的执行入口,线程不能独立执行,必须依赖进程

上下文切换:任务从保存到再加载的过程就是一次上下文切换。

3、创建线程的四种方式

  • 继承Thread
  • 实现Runnable接口
  • 实现Callable接口
  • 使用Executors工具类创建线程池

Runnable和Callable区别

相同点:

  • 都是接口;
  • 都可以编写多线程程序;
  • 都采用Thread.start()启动线程

不同点

  • Runnable接口的run()方法没有返回值 ;Callable()接口的call()方法有返回值,是个泛型
  • Runnable接口run()方法只能抛出运行时异常,且无法捕捉处理;Callable接口call()方法允许抛出异常,可以获取异常信息

线程的run()和start()有何区别

  • start()用于启动线程,run()用于执行线程运行时的代码。run()方法可以重复调用,start()只能调用一次
  • start()方法用于启动线程,真正实现了多线程的运行。调用start()时无需等待run()方法方法体代码执行完毕就可以执行其他代码;此时线程是就绪态,并没有开始运行,然后通过Thread类调用run()方法完成其运行状态,run()方法运行结束,此线程就终止了
  • run()方法是在线程里的,直接调用run()方法,相当于调用了一个普通的函数,必须等待run()方法执行完毕才可以执行下面的代码,所以执行路径还是一条,没有多线程的特征,所以在线程启动时,要调用start()方法而不是run()方法。

Future和FutureTask

  • Callable接口的call()方法有返回值,Future可以拿到异步执行任务(这个任务也许并没有完成)的返回值,并且可以抛出异常信息。
  • FutureTask是Future的具体实现。FutureTask实现了RunnableFuture接口。RunnableFuture接口又同时继承了Future和 Runnable接口。所以FutureTask既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

4、线程的状态和基本操作

线程的五种状态和生命周期

在这里插入图片描述

  • 新建(new)
  • 可运行/就绪态(runnable):调用start()方法后就处于Runnable态
  • 运行(running):runnable态获取到时间片,就进入running态;就绪态是进入运行态的唯一入口,线程要进入运行态就必须要进入就绪态
  • 阻塞(block)
  • 死亡(dead):死亡的线程不可复生

线程调度的方法

1、wait():使一个线程处于阻塞等待状态,并且释放所持有的对象锁
2、sleep():使役个正在运行的线程处于睡眠状态,是一个静态方法
3、notify():唤醒一个处于等待队列的线程,再调用此方法时,并不能确切的唤醒某个等待的线程,由JVM确定唤醒哪个线程,并且与优先级无关
4、notifyAll():唤醒所有处于等待队列的线程,然后重新竞争锁

wait()和sleep()区别

  • 所在类不同:sleep()是Thread类的静态方法;wait()是Object类的方法
  • 锁:sleep()不释放锁,wait()释放锁
  • 用途:wait()用于线程之间通信;sleep()用于暂停线程执行
  • 用法不同:wait()在结束后,不会自动苏醒,需要别的线程调用同一个对象上的notify()或者notifyAll()去唤醒;而sleep()方法在结束后,自动苏醒。

interrupt()、interrupted()、isInterrupted()

  • interrupt()、isInterrupted()是通过Thread对象调用,是实例方法;interrupted()是通过Thread类调用,是静态方法
  • interrupt()方法,只是通知该线程停止运行,只是通知,并没有直接中断,而是由程序自己决定是否中断

线程类的构造方法、静态代码块是被new这个线程的类的线程所调用的(谁new谁调用),run()方法是自身线程调用

5、synchronized

作用:用来控制线程同步的,被synchronized修饰的代码不能被多个线程同时执行,可以修饰类、方法、变量

synchronized底层原理

synchronized修饰的代码在反编译为字节码文件时,前后都出现了monitor字样,前面出现的是monitorenter,后面出现的是monitorexit,就是释放锁。当执行monitorenter时,当前线程试图获取对象锁所持有的monitor,当计数器为0时,就可以成功获取,当获取到时,计数器+1。并且就算当前线程已经拥有对象锁的monitor的持有权,那么就可以重入这个monitor,重入计数器也会加一。如果其他线程占有monitor持有权,那么当前线程就会阻塞,知道其他线程执行monitorexit,执行后锁释放,计数器设置为0。

自旋

即其他线程不进入阻塞态,而是在synchronized边界循环等待,不断尝试获取锁,这就是自旋

synchronized锁升级

synchronized涉及到用户态和内核态的切换,在1.6之前,锁都是重量级锁,即我们不管什么线程来操作资源,都要进行加锁释放锁,如果有多线程,还要等待之类的,很浪费资源,1.6之后引入了偏向锁与轻量锁来减小获取和释放锁所带来的性能消耗。

锁升级其实就是对synchronized的优化,以前用synchronized修饰一个对象或者是方法,方法也等于是锁住对象,直接用一把操作系统层面的大锁,万一只有少量线程的话会大题小作了,如果大量线程的话又会特别消耗时间,划不来,所以要将以前的二话不说用一把大锁进行优化。

无锁->偏向锁->轻量级锁->重量级锁

原理:在锁对象的对象头有一个threadid字段,第一次访问时threadid为空,JVM让其持有偏向锁,并把threadid设置为线程id,再次进入时只需要判断两个id是否相等,相等就直接进入,不相等就升级为轻量级锁;自旋一段时间后还没有获取到就升级到重量级锁。

synchronized、volatile、CAS区别

  • synchronized是悲观锁,属于抢占式,会引起其他线程阻塞
  • volatile提供多个线程共享变量可见性和禁止指令重排序
  • CAS是基于冲突监测的乐观锁(非阻塞)

synchronized、Lock、ReentrantLock区别

  • synchronized、ReentrantLock都是可重入锁
  • synchronized是关键字,Lock是接口,ReentrantLock是实现了Lock接口的一个类
  • synchronized可以给类、方法、代码块加锁,Lock和ReentrantLock只能给代码块加锁
  • synchronized不用手动获取和释放,发生异常会自动释放锁,不会造成死锁;Lock和ReentrantLock需要手动,没有unLock()就会死锁
  • Lock可以知道是否成功获取到锁,synchronized不行

6、volatile

保证可见性和禁止指令重排序,提供happens-before的保证,确保一个线程的修改对于其他线程是可见的。被volatile修饰的共享变量,当它被修改时,可以将修改的值立即更新到主内存中,其他线程需要读取时,重新去主内存中读取新值
volatile可以保证可见性和禁止重排序,但不能保证原子性;atomic方法可以让这种方法具有原子性

7、Lock体系

Lock是synchronized的扩展版本,Lock提供了无条件的、可轮询的(tryLock方法)、定时的(tryLock带参方法)、可中断的(lockInterruptibly)、可多条件队列的锁操作。Lock的实现基本都支持公平锁和非公平锁,synchronized只支持非公平锁

  • 悲观锁:悲伤的假设最坏的情况,每次拿数据都认为别人会修改,所以在拿的时候就会加锁,别人想拿就阻塞(共享资源每次只给一个线程使用,其他线程阻塞,用完再把资源转让给其他线程)
  • 乐观锁:每次拿数据,不会上锁,直到提交数据时才会证实数据是否被修改(产生并发冲突),多用于多读场景。一般用版本号或者CAS实现

8、CAS

CompareAndSweep——比较并交换
CAS包含三个操作数——内存位置(V)、预期值(A)、拟写入的新值(B)

  • 第一步:比较V和A是否相等
  • 第二步:相等,就把B写入V
  • 第三步:返回boolean类型,表示操作成功

多个线程进行CAS操作时,只有一个线程可以操作成功,其他线程自旋等待

CAS产生的问题

  • ABA问题:从A变到B,再从B变到A,过程不知道;解决办法:引入版本号
  • 循环开销时间大:资源竞争严重时,CAS自旋概率大,浪费CPU
  • 只能保证一个共享变量的原子性操作

9、线程死锁

两个或以上的线程互相持有对方资源并且不主动释放造成的恶性循环

死锁的四个条件

  • 互斥条件:一个资源只能被一个线程占用
  • 请求与保持条件:请求被占用资源而阻塞,不放弃已经获得的资源
  • 不剥夺条件:资源未使用前不能被其他线程强行剥夺
  • 循环等待条件:等待的线程形成了一个死循环

避免死锁

破坏造成死锁四个条件中的一个就行

  • 互斥条件无法破坏
  • 破坏请求与保持条件:一次性申请所有资源
  • 破坏不剥夺条件:申请不到被占用的资源,就主动释放
  • 破坏循坏等待条件:

活锁

没有被阻塞,只是某些条件没满足,导致一直重复尝试、失败、尝试、失败这个过程
活锁有可能自己解开,死锁不能

饥饿

因为种种原因无法获取到所需要的资源,导致一直无法执行

10、ThreadLocal

为线程提供局部变量,保证各个线程里的变量独立于其他线程的变量,也就是说ThreadLocal为每个线程创建一个单独的副本,线程之间不相关,
同步机制是为了保证多线程环境下数据的统一性,而ThreadLocal则是保证多线程环境下数据的独立性

ThreadLocal底层原理

Thread类中有一个ThreadHashMap的数据结构,用来保存线程对象的变量
每个线程的ThreadHashMap都是属于线程自己的,这就保证了每个线程都是独立的,多个操作不会互相影响

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

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

相关文章

C++ 网络编程

一、Reactor 网络编程模型 reactor 是一个事件处理模型。网络处理:因为用户层并不知道 IO 什么时候就绪,所以将对 IO 的处理转化为对事件的处理。网络模型构成: 非阻塞 IO:操作 IO,如果 IO 未就绪,IO 函数会立刻返回。IO 多路复用:检测多路 IO 是否就绪。工作流程: 注册…

【设计模式】JAVA Design Patterns——Bridge(桥接模式)

🔍目的 将抽象与其实现分离,以便二者可以独立变化。 🔍解释 真实世界例子 考虑一下你拥有一种具有不同附魔的武器,并且应该允许将具有不同附魔的不同武器混合使用。 你会怎么做? 为每个附魔创建每种武器的多个副本&…

每周刷题第三期

个人主页:星纭-CSDN博客 系列文章专栏:Python 踏上取经路,比抵达灵山更重要!一起努力一起进步! 目录 题目一:环形链表 题目二:删除有序数组中的重复项 题目三:有效的括号 题…

【C语言】程序员自我修养之文件操作

【C语言】程序员自我修养之文件操作 🔥个人主页:大白的编程日记 🔥专栏:C语言学习之路 文章目录 【C语言】程序员自我修养之文件操作前言一.文件介绍1.1为什么使用文件1.2文件分类1.3二进制文件和文本文件 二.文件的打开和关闭2.…

docker-compose Install homer

homer前言 一个非常简单的静态主页,为您的服务器保持您的服务在手,从一个简单的yaml配置文件。 前提要求 安装 docker docker-compose 参考创建一键安装homer 脚本 homer安装位置/homerhomer 脚本位置/homer/assetshomer logo 图标/home/assets/iconshomer 端口80homer 颜色…

连续三次拒绝饭局的邀请,不会在有人请你吃饭!

人们对于饭局的态度各有不同,有的认为饭局纯属浪费时间,还有各种套路,应该尽量少参加。也有的人认为饭局是沟通感情的平台,有这样的机会应该尽量去参与。不管是否喜欢饭局,但总要时不时去参加的。如果你连续三次拒绝饭…

文心智能体应用示例:职场反PUA专家的诞生

🧑 博主简介:阿里巴巴嵌入式技术专家,深耕嵌入式人工智能领域,具备多年的嵌入式硬件产品研发管理经验。 📒 博客介绍:分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向…

JAVA开发 基于最长公共子序列来计算两个字符串之间的重复率

计算两个字符串之间的重复率 最长公共子序列实现代码 最长公共子序列 基于最长公共子序列(Longest Common Subsequence, LCS)的重复率的中心逻辑是首先找到两个或多个序列中同时出现的、不一定连续但保持相对顺序的最长子序列,然后计算这个最…

知识获取概述

文章目录 知识获取研究现状技术发展趋势 知识图谱主要技术包括知识获取、知识表示、知识存储、知识建模、 知识融合、知识理解、知识运维等七个方面,通过面向结构化、半结构化和非结构化数据构建知识图谱为不同领域的应用提供支持,具体的技术架构图如下图…

全栈安全 为云而生 | 亚信安全信舱ForCloud全新品牌重磅发布

5月18日,亚信安全云安全全新品牌ForCloud正式发布。基于“全栈安全 为云而生”的创新理念,亚信安全云安全完成全新、全面、全栈升级。ForCloud的发布仪式在C3安全大会“云领未来:全栈一体化”云安全论坛上隆重举办,同时亚信安全还…

许冉直播不治本,京东需要刘强东

图片|影视剧《纸牌屋》剧照 ©自象限原创 作者丨艾AA 编辑丨薛黎 这届618,消费者的热情还未显现,商家的怒火先爆发了。 5月21日京东618开幕次日,多家图书社抵制618图书大促登上了热搜。此次争议与去年双十一京东采销与电…

执行sql脚本——kettle开发03

一、转换对象的优先级 kettle中转换和作业的执行顺序: 1、一个作业内的转换,是顺序执行的。 2、一个转换内的步骤是并行执行的。 3、作业内不支持事务,转换内支持事务。 根据业务需要,通常需要在转换内顺序执行,小技巧…

Java进阶-SpringCloud使用BeanUtil工具类简化对象之间的属性复制和操作

在Java编程中,BeanUtil工具类是一种强大且便捷的工具,用于简化对象之间的属性复制和操作。本文将介绍BeanUtil的基本功能,通过详细的代码示例展示其应用,并与其他类似工具进行对比。本文还将探讨BeanUtil在实际开发中的优势和使用…

Go微服务开发框架DMicro的设计思路

DMicro是一个基于Go语言开发的微服务开发框架,旨在简化微服务架构的开发、部署和运维过程。DMicro的设计思路主要围绕以下几个方面展开: 简化微服务开发流程 DMicro通过提供一套简洁的API和工具,使得开发者可以快速搭建微服务应用。它支持服…

景源畅信电商:抖店需要的成本高吗?

在数字化时代的浪潮中,短视频平台迅速崛起,成为连接用户与商家的新桥梁。抖音作为其中的佼佼者,不仅改变了人们的娱乐方式,也催生了新型的电商模式——抖店。许多人好奇,入驻这样一个充满活力的平台,需要承…

jwtcracker下载安装出现错误

1.jwtcracker 用于爆破jwt秘钥 2.下载 ubuntu/kali安装c-jwt-cracker及使用方法-CSDN博客 参考这个大佬写的 但是我在这里出现了这个问题 显示Cannot initialize the default message digest sha256, aborting 我实在找不出来哪里有问题,所以直接换成docker …

C++进阶:C++11(列表初始化、右值引用与移动构造移动赋值、可变参数模版...Args、lambda表达式、function包装器)

C进阶:C11(列表初始化、右值引用与移动构造移动赋值、可变参数模版…Args、lambda表达式、function包装器) 今天接着进行语法方面知识点的讲解 文章目录 1.统一的列表初始化1.1{}初始化1.2 initializer_listpair的补充 2.声明相关关键字2.1a…

springboot+vue2+elementui实现时间段查询

1.前端代码 使用elementui的时间段选择器&#xff1a; <el-date-picker v-model"queryPage.itemTime" type"daterange"value-format"yyyy-MM-dd" class"filter-item" range-separator"至" start-placeholder"创建…

Python筑基之旅-MySQL数据库(三)

目录 一、数据库操作 1、创建 1-1、用mysql-connector-python库 1-2、用PyMySQL库 1-3、用PeeWee库 1-4、用SQLAlchemy库 2、删除 2-1、用mysql-connector-python库 2-2、用PyMySQL库 2-3、用PeeWee库 2-4、用SQLAlchemy库 二、数据表操作 1、创建 1-1、用mysql-…

Kubernetes常用命令

目录 一.资源管理办法 1.陈述式资源管理方法 &#xff08;1&#xff09;kubernetes 集群管理集群资源的唯一入口是通过相应的方法调用 apiserver 的接口 &#xff08;2&#xff09;kubectl 是官方的CLI命令行工具&#xff0c;用于与 apiserver 进行通信&#xff0c;将用户在…