什么是线程安全,解决线程安全的方法

什么是线程安全,解决线程安全的方法 前言来自我对一位我所崇拜的大佬文章的评论:我:“喝罢黄河之水天上来,酒醒杨柳残月且偷欢,唱罢笑傲江湖祭沧海,雁渡寒潭有几只回还”大佬:“年少正恰,纵码飞骋,略江山华月,有几人随傅虎

前言

来自我对一位我所崇拜的大佬文章的评论:

我:“喝罢黄河之水天上来,酒醒杨柳残月且偷欢,唱罢笑傲江湖祭沧海,雁渡寒潭有几只回还”

大佬:“年少正恰,纵码飞骋,略江山华月,有几人随傅虎踞龙盘。”


进入正题

线程或者锁在并发编程中的作用,类似于铆钉和工字梁在土木工程中的作用。要建筑一座坚固的桥梁,必须正确地使用大量的铆钉和工字梁。同理,在构建稳健的并发程序时,必须正确地使用线程和锁。但这些终归只是一些机制。要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享(Shared)和可变的(Mutable)状态的访问。

  • 对象的状态:指存储在状态变量中的数据,当然也可能包含其他依赖对象的域。 例如,某个 HashMap 的状态不仅存储在 HashMap 对象本身,还存储在许多 Map.Entry 对象中。在对象的状态中包含了任何可能影响其外部可见行为的数据。
  • 共享Shared:共享意味着变量可以有多个线程同时访问。
  • 可变Mutable:意味着变量的值在其生命周期内可以发生变化。

注释:讨论线程安全性,更应该侧重于如何防止在数据上发生不受控的并发访问。一个对象是否需要是线程安全的,取决于他是否被多个线程访问。(指的是在程序中访问对象的方式,而不是对象要实现的功能)

当多个线程访问某个状态变量并且其中有一个线程执行写入操作时,必须采用同步机制来协同这些线程对变量的访问。

  • 关键字 synchronized:提供独占的加锁方式。
  • voatile 类型变量:同步应该要包括的还有,显式锁(Explicit Lock)以及原子变量。

如果忽略了某一个同步的机制,可能会造成的后果,当多个线程访问同一个可变的状态变量时没有使用合适的同步,程序就会出错,修复:

  • 不在线程之间共享该状态变量
  • 将状态变量修改为不可变的变量
  • 在访问状态变量时使用同步

注释:当设计线程安全的类时,良好的面向对象技术、不可修改性,以及明晰的不变形规范都能起到一定的帮助作用。

在编写并发应用程序时,一种正确的编程方法就是:首先代码正确运行,然后再提高代码速度。即便如此,最好也只是当性能测试结果和应用需求告诉你必须提高性能,以及测量结果表明这种优化在实际环境中确实能带来性能提升时,才进行优化。


什么是线程安全性

我们都知道:定义越正式,就越复杂,不仅很难提供由实际意义的指导建议,而且也很难从直观上去理解。网上的“定义”有很多,比如:

  • ······ 可以在多个线程中调用,并且在线程之间不会出现错误的交互。
  • ······ 可以同时被多个线程调用,而调用者无须执行额外的动作。

也难怪我们会对线程安全性感到困惑,因为听起来就想“如果某个类可以在多个线程中安全的使用,那么它就是一个线程安全的类。”虽然不存在很多争议,但是有什么实际的意义和帮助么。

“安全”的含义是什么:

  • 在线程安全的定义中,最核心的概念就是正确性。
  • 正确的含义是——某个类的行为与其规范完全一致

我将单线程的正确性近似定义为“所见即所知”,在对“正确性”给出了一个较为清晰的定以后,就可以定义线程安全性:

  • 当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。
  • 当多个线程访问某个类时,不关于刑事环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称呼这个类是线程安全的。
  • 由于单线程程序也可以看成多线程程序,若某个类在单线程环境下都不是正确的,那么它肯定不会是线程安全(也就是说一个程序首先要能正常的工作保证正确性)。

简单的示例

通常,线程安全性的需求并非来源于对县城的直接使用,而是使用像 Servlet 这样的框架(还有很多)。

一个基于 Servlet 的因数分解服务,并逐步扩展功能,并确保它的线程安全性。

一个无状态的 Servlet:

@ThreadSafe
public class StatelessFactorizer implements Servlet {
	public void service(ServletRequest req,ServletResponse resp) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = factor(i);
        encodeIntoResponse(resp,factors);
	}
}

与大多数 Servlet 相同,StatelessFactorizer 是无状态的,它既不包含任何域,也不包含任何对其他类中域的引用。计算过程中的临时状态仅存在于线程栈上的局部变量中,并且只能由正在执行的线程访问。访问 StatelessFactorizer 的线程不会影响另外一个访问同一个 StatelessFactorizer 的线程的计算结果 ,因为这两个线程并没有共享状态,就好像他们都在访问不同的实例。由于线程访问无状态对象的行为并不会影响其他线程中操作的正确性,因此无状态对象是线程安全的。

  • 无状态对象一定是线程安全的。
  • 大多数 Servlet 都是无状态的,从而极大地降低了在实现 Servlet 线程安全性时的复杂性。只有当 Servlet 在处理请求时需要保存一些信息线程安全性才会成为一个问题。

作者:Sunny_Chen链接:https://juejin.cn/post/6999423430462275592

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/86994.html

(0)

相关推荐

  • 哈弗预售款13.2万从99元定金一到十。

    文章长度:0太短了,请勿浪费资源

    科技 2021年12月9日
  • 嘀嘀礼品价格明细表嘀嘀最佳礼品排行榜

    是抖音礼物价格明细表 抖音最贵礼物排名。 嘀嗒送礼物有很多选择,但根据礼物的价格而不同。 为您介绍嘀嗒礼品价目表的详细内容。 快来看看吧。 : 礼物价格表明细 小心心,玫瑰,抖音,...

    2022年11月10日
  • 感冒食谱做法大全 感冒食谱教程大全

    感冒食谱做法大全 感冒食谱教程大全2021-10-28 09:58:251、做法一用料:鸡蛋、香油适量、姜末适量。把香油倒入锅内烧开后,加入少许姜末,炒香。然后打入鸡蛋,炒熟即可。需要注意,不能添加任何的调味品!2、做法

    生活 2021年10月28日
  • idc鏈烘埧,edc机房与idc

    综合edc机房与idc1、云计算中心中的IDC中心和EDC中心的区别 搜狗问问数据中心从建设用途上可分为IDC和EDC两类.IDC(Internet Data Center)指提供互联网服务的数据中心,通常以第三方托管形

    生活 2022年1月25日
  • 问道手游不开会员刷道给金币吗,问道手游金币怎么买会员

    问道手游会员给的金币多吗2021问道手游出金攻略?网友分享:2、降妖+伏魔:四十五-八十降妖,八十级之上伏魔,开通会员给金币,单号至少1000万之上;伏魔前四百次,以七十五级号为例子通常给金币一次均值1.5万左右,总。问道手游搬砖收益怎么算?网友分享:游戏账号一般100开起步(个人),不充会员,当然金币会少很多。 押镖1个号最低600万金币到1200万金币,一般平均会做到1000万左右,100个号就是10亿。 帮派必做有。问道手游会员卡干什么的?网友分享:07、无限制切换任何线路 无会员1线基本进不去 08、聊天可以选择变换字体颜色 09、会员玩家师门任务 修山所得到的金钱为可交易金币 不是会

    阅读 2022年7月4日
  • 我的世界泰坦生物MOD

    我的世界泰坦生物MOD是为游戏《我的世界》开发的游戏MOD。 该MOD可以将游戏中的骷髅射手、蜘蛛等怪物变成与泰坦比肩的超巨大生物,具有无与伦比的气势和压迫,具有非常好的视觉效果。...

    2022年10月31日