首先我们要了解什么是线程安全:

首先我们要明白线程的工作原理,jvm有一个main  memory ,而每个线程有自己的working memory,一个线程对一个variable  进行操作时,都要在自己的working memory 里面建立一个copy,操作完之后再写入main memory. 多个线程同时操作同一个variable ,就可能会出现不可预知的结果,根据上面的解释,很容易出现相应的scenario .而用synchronized的关键是建立一个monitor,这个monitor可以是要修改的variable也可以其他你认为合适的object比如method,然后通过给这个monitor加锁来实现线程安全,每个线程在获得这个锁之后,要执行完   load到workingmemory   ->   use&assign   ->   store到mainmemory   的过程,才会释放它得到的锁。这样就实现了所谓的线程安全。

什么是线程安全?

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

  或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。

  线程安全问题都是由全局变量及静态变量引起的。

  若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。

举例 比如一个 ArrayList 类,在添加一个元素的时候,它可能会有两步来完成:

1. 在 Items[Size] 的位置存放此元素;

2. 增大 Size 的值。

线程安全性:

类要成为线程安全的,首先必须在单线程环境中有正确行为,如果一个类实现正确,那么没有一种对这个类的对象操作序列,可以让对象处于无效状态,观察到对象处于无效状态,或者违反类的任何不可变量,前置条件或者后置条件的情况

此外,一个类要成为线程安全的,在被多个线程访问时,不管运行时环境执行这些线程有什么样的时序安排或者交错,他必须仍有如以上所述的正确行为,并且在调用的代码中没有任何额外的同步.其效果就是,在所有线程看来,对于线程安全对象的操作是以固定的,全句一直的顺序发生的

正确性与线程安全性之间的关系非常类似于在描述 ACID(原子性、一致性、独立性和持久性)事务时使用的一致性与独立性之间的关系:从特定线程的角度看,由不同线程所执行的对象操作是先后(虽然顺序不定)而不是并行执行的。

线程安全程度  

线程安全性不是一个非真即假的命题。 Vector 的方法都是同步的,并且 Vector 明确地设计为在多线程环境中工作。但是它的线程安全性是有限制的,即在某些方法之间有状态依赖(类似地,如果在迭代过程中 Vector 被其他线程修改,那么由 Vector.iterator() 返回的 iterator会抛出ConcurrentModifiicationException)。

  对于 Java 类中常见的线程安全性级别,没有一种分类系统可被广泛接受,不过重要的是在编写类时尽量记录下它们的线程安全行为。

  Bloch 给出了描述五类线程安全性的分类方法:不可变、线程安全、有条件线程安全、线程兼容和线程对立。只要明确地记录下线程安全特性,那么您是否使用这种系统都没关系。这种系统有其局限性 -- 各类之间的界线不是百分之百地明确,而且有些情况它没照顾到 -- 但是这套系统是一个很好的起点。这种分类系统的核心是调用者是否可以或者必须用外部同步包围操作(或者一系列操作)。下面几节分别描述了线程安全性的这五种类别。

不可变

  不可变的对象一定是线程安全的,并且永远也不需要额外的同步[1]。因为一个不可变的对象只要构建正确,其外部可见状态永远也不会改变,永远也不会看到它处于不一致的状态。Java 类库中大多数基本数值类如 Integer 、 String 和 BigInteger 都是不可变的。

线程安全

  线程安全的对象具有在上面“线程安全”一节中描述的属性 -- 由类的规格说明所规定的约束在对象被多个线程访问时仍然有效,不管运行时环境如何排列,线程都不需要任何额外的同步。这种线程安全性保证是很严格的 -- 许多类,如 Hashtable 或者 Vector 都不能满足这种严格的定义。

有条件的线程安全

  有条件的线程安全类对于单独的操作可以是线程安全的,但是某些操作序列可能需要外部同步。条件线程安全的最常见的例子是遍历由 Hashtable 或者 Vector 或者返回的迭代器 -- 由这些类返回的 fail-fast 迭代器假定在迭代器进行遍历的时候底层集合不会有变化。为了保证其他线程不会在遍历的时候改变集合,进行迭代的线程应该确保它是独占性地访问集合以实现遍历的完整性。通常,独占性的访问是由对锁的同步保证的 -- 并且类的文档应该说明是哪个锁(通常是对象的内部监视器(intrinsic monitor))。

  如果对一个有条件线程安全类进行记录,那么您应该不仅要记录它是有条件线程安全的,而且还要记录必须防止哪些操作序列的并发访问。用户可以合理地假设其他操作序列不需要任何额外的同步。

线程兼容

  线程兼容类不是线程安全的,但是可以通过正确使用同步而在并发环境中安全地使用。这可能意味着用一个 synchronized 块包围每一个方法调用,或者创建一个包装器对象,其中每一个方法都是同步的(就像 Collections.synchronizedList() 一样)。也可能意味着用 synchronized 块包围某些操作序列。为了最大程度地利用线程兼容类,如果所有调用都使用同一个块,那么就不应该要求调用者对该块同步。这样做会使线程兼容的对象作为变量实例包含在其他线程安全的对象中,从而可以利用其所有者对象的同步。

  许多常见的类是线程兼容的,如集合类 ArrayList 和 HashMap 、 java.text.SimpleDateFormat 、或者 JDBC 类 Connection 和 ResultSet 。

线程对立

  线程对立类是那些不管是否调用了外部同步都不能在并发使用时安全地呈现的类。线程对立很少见,当类修改静态数据,而静态数据会影响在其他线程中执行的其他类的行为,这时通常会出现线程对立。线程对立类的一个例子是调用 System.setOut() 的类。

转载于:https://www.cnblogs.com/zsping/p/5556113.html

专业写博一天------ArrayList 线程安全相关推荐

  1. 坚持写博客给我带来了什么

    从16年4月来深圳之后我就开始写博客,最开始写博客的阵地是在简书.简书以它良好的写作体验和简洁的博客展示界面吸引了我.我在简书坚持写了一年,大概写了60篇文章,字数在五万字左右,文章质量中等偏下,纯粹 ...

  2. 要上进总会有时间的,要放松也总会有理由的——记录2年出版2本书带给我的改变,同时分享写书和写博客的技巧...

    2年前,我其实是很开心的,人在外企,加班不多,晚上下班后就躺在沙发上电视或刷连续剧.周末除了出去讲课挣外快,一般也时玩游戏为主,经常会一个下午加晚上,先玩游戏再下棋再看片再听歌.结果发现我的能力脱节了 ...

  3. 学生为什么要在CSDN写博客?

    学生为什么要在CSDN写博客? 引言 写博客的好处 构建知识体系 提升写作能力 扩展人脉 为简历加分 帮助他人 为什么是CSDN 如何写博客 记录学习 总结错误 总结与展望 引言 就目前来说,学生应该 ...

  4. 决心开始写博,坚持!

    胡子是一个充满人性弱点的有志青年,或者更具体的说,是一个对未来充满美好愿景的的空想主义者.之所以这么说,是因为胡子发现自己经常会被"懒惰"."贪婪"和" ...

  5. 做为技术人员为什么要写博客?

    做为技术人员为什么要写博客? 本文只代表个人见解,不代表任立场,如果您认为我的想法是错的那很正常,因为这是我的想法,如果您觉得您的想法和我一样,那我们就是传说中的 "激友"(对生活 ...

  6. 【24小时内第四更】为什么我们要坚持写博客?

    前言 从2018年7月份,我开始了写作博客之路.开始之前,我打算分享下之前的经历.去年初公司来了个架构师,内部分享过docker原理,TDD单元测试驱动,并发并行异步编程等内容,让我着实惊呆了,因为确 ...

  7. 如何使ArrayList 线程安全

    转载自  如何使ArrayList 线程安全 ArrayList是线程不安全的,轻量级的.如何使ArrayList线程安全? 1.继承Arraylist,然后重写或按需求编写自己的方法,这些方法要写成 ...

  8. 为什么到今天还要坚持写博客(转)

    几年前,写博客是非常流行的,但是自从Facebook和Twitter出现之后,它显然有些失宠.但我想告诉你,到今天你都应该开设你自己的博客,如果你有自己的博客,但有一段时间没有更新了,你应该回到那里并 ...

  9. 【杂记】我为什么要坚持写博客

    从二月份开始写第一篇博客到现在,在CSDN已经发表十篇博客了,算是坚持走出了"第一步".昨天在健身的时候,一边跑步一边在想"博客要继续写下去". 为什么要坚持写 ...

最新文章

  1. 【Netty】入门Netty官方例子解析(一)写个 Discard Server
  2. ubuntu声卡相关
  3. Ubuntu下添加定时任务执行php文件
  4. helm3 helm-push插件安装及基本使用
  5. 简单实现KeyChain实例
  6. vfp赋值超过7位出错_JDK1.7下的HashMap的源码分析
  7. webapp 微信开发适配问题
  8. scrapy自定义Request的缓存策略(减少内存占用)
  9. python中面向对象的缺点_面向对象中的多态在 Python 中是否没有什么意义?
  10. Q113:PBRT-V3分别在Linux和Mac下的编译与调试(汇总)
  11. CLR Via CSharp读书笔记(11):事件
  12. C++数据结构之图的储存结构——十字链表
  13. firefox硬件加速 linux,全面启用 Firefox Youtube视频硬件加速
  14. 资源池、虚拟机、集群的关系
  15. 根据录入的计算公式计算_增值税含税怎么计算?
  16. jq插件,图片或者视频懒加载
  17. 《期权、期货及其他衍生产品》读书笔记(第二章:期货市场与中央交易对手)
  18. 基于STM32F03RCT的多路频率占空比可调PWM输出
  19. centos挂载盘到根下_centos挂载磁盘及扩展根目录
  20. 化工厂人员定位系统,有效提高化工安全

热门文章

  1. 分布式事务 TCC-Transaction 源码分析 —— 项目实战
  2. Shell中的${ }、#、##、%、%%使用范例
  3. iOS应用间相互跳转
  4. LeetCode——Contains Duplicate III
  5. 如何更好的利用Node.js的性能极限
  6. 控制器中添加DB类才可以操作数据库表中的数据
  7. Python OS 文件操作模块常用函数
  8. Linux查看文件夹大小的相关命令
  9. java读取 500M 以上文件,java读取大文件
  10. 打开word或者office程序报错:Microsoft Visual C++ Runtime Library. Runtime Error!