我们不仅仅希望防止某个线程使用某个状态时,另一个线程在修改它;我们还希望某个线程修改了某个状态后,其他线程能够看到状态的变化。

一、可见性

重排序:在没有同步的情况下,编译器、处理器可能对代码的执行顺序进行一些调整

例如如下代码,由于没有使用同步机制,读线程可能看不见ready的修改,而一直循环下去;也可能由于重排序,看到了ready的修改number仍没修改而输出0

1、失效数据

在缺少同步的程序中产生错误的结果的一种情况。造成程序的不确定性

2、非原子的64位操作

即使是失效数据也是程序过去运行中产生的数据。

但执行非原子的64位操作,JVM会分解为两个32位操作,从而可能造成错误的值。使用volatile关键字解决

3、加锁与可见性

加锁的作用不仅仅局限在互斥,还包括内存可见性。

锁可以确保某个线程以一种可以预测的方式来查看另一个线程的执行结果。即前一线程结果后一线程可见。

4、volatile变量

比synchronized更轻量级的同步机制,编译器和运行时都会注意到这个变量是共享的,在该变量上的操作和其他内存操作不会放在一起做重排序

读取volatile变量的开销很小。

在开发阶段最好时候server模式,因为server模式会做更多的优化,例如重排序等可能导致并发问题

加锁机制能保证可见性和原子性,volatile只能保证可见性,使用条件:

  • 写入不依赖当前值
  • 访问时不用加锁

二、发布与逸出

发布:使对象能够在当前作用于外的代码使用,例子:

逸出:不该发布的对象被发布

不要在构造方法中使this的引用溢出,会发布一个不完整的对象

三、线程封闭

当访问共享的可变数据时,通常需要同步。一种避免使用同步的方式就是不共享数据。如果仅在单线程内访问数据,就不需要同步。这种技术称为线程封闭

需确保封闭在线程中的对象不会溢出

1、Ad-hoc线程封闭:完全有程序实现线程封闭,少用

2、栈封闭:只能通过局部变量访问对象,因为其他线程无法访问执行线程的栈区域

3、TheadLocal类ThreadLocal<T> -> Map<Thread, T>

ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量。

详见:(转)http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E4%B8%83]%E8%A7%A3%E5%AF%86ThreadLocal/

四、不变性

满足同步需求的另外一种方法是使用不可变对象。不可变对象一定是线程安全的

不可变对象:对象创建出来后无论如何对此对象进行非暴力操作(不用反射),此对象的状态(实例域的值)都不会发生变化,那么此对象就是不可变的,相应类就是不可变类,跟是否用 final 修饰没关系。(例:final域中保存了可变对象的引用)

条件:对象创建后状态不更改;域均用final修饰;正确创建(构造函数没有this溢出)

1、final域

2、通过volatile发布不可修改对象实现线程安全

因为cache是不可修改的,所以可以保证每个i和factors是对应的,并用volatile保证了可见性

五、安全发布

1、不正确的发布,正确对象被破坏

  未被创建完成的正确对象被发布,其他线程可能看到一个失效的值或空指针

2、不可变对象与初始化安全性

  任何线程都可以在不需要同步的情况下访问不可变对象,即使发布不可变对象时没有同步

3、安全发布的常用模式

  可变对象通过安全的方式发布,即发布和使用他的线程必须进行同步

  发布静态对象时,使用静态初始化器,由JVM在累得初始化时执行,并且存在同步机制

  将对象的引用保存到volatile类型或AtomicReferance对象中或正确构造的final中

  将对象发布到有锁保护的域中(HashTable,synchronizedMap,ConcurrentMap,Vector,CopyOnWriteArrayList,CopyOnWriteArraySet,synchronizedList,synchronizedSet,BlockingQueue,ConcurrentLinkedQueue)

4、事实不可变对象:技术上可变,实际不会变

  任何线程都可以在不需要同步的情况下访问安全发布的事实不可变对象

5、可变对象

  需要安全发布,并且访问需要同步机制

6、安全的共享对象

java并发编程实战:第三章----对象的共享的更多相关文章

  1. Java并发编程实战 第3章 对象的共享

    可见性 可见性是由于java对于多线程处理的内存模型导致的.这似乎是一种失败的设计,但是JVM却能充分的利用多核处理器的强大性能,例如在缺乏同步的情况下,Java内存模型允许编译器对操作顺序进行重排序 ...

  2. JAVA并发编程实战---第三章:对象的共享(2)

    线程封闭 如果仅仅在单线程内访问数据,就不需要同步,这种技术被称为线程封闭,它是实现线程安全性的最简单的方式之一.当某个对象封闭在一个线程中时,这种方法将自动实现线程安全性,即使被封闭的对象本生不是线 ...

  3. JAVA并发编程实战---第三章:对象的共享

    在没有同步的情况下,编译器.处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整.在缺乏足够同步的多线程程序中,要对内存操作的执行顺序进行判断几乎无法得到正确的结果. 非原子的64位操作 当 ...

  4. Java并发编程实战 第4章 对象的组合

    Java监视器模式 java监视器模式就是在将共享的数据封装在一个类里面,然后然后所有访问或者修改这些数据的方法都标注为synchronize. 车辆追踪模拟: 使用监视器模式: CarTracker ...

  5. 读书笔记-----Java并发编程实战(二)对象的共享

    public class NoVisibility{ private static boolean ready; private static int number; private static c ...

  6. 【JAVA并发编程实战】1、对象的共享

    1.栈封闭 在栈封闭中,只能通过局部变量才能访问对象. 所谓栈封闭就是把变量的声明以及应用都局限在一个局部线程中,在这个局部线程中声明和实例化的对象对于线程外部是不可见的,这个局部线程的栈,无法被任何 ...

  7. Java并发编程实战---第六章:任务执行

    废话开篇 今天开始学习Java并发编程实战,很多大牛都推荐,所以为了能在并发编程的道路上留下点书本上的知识,所以也就有了这篇博文.今天主要学习的是任务执行章节,主要讲了任务执行定义.Executor. ...

  8. Java并发编程实战 第16章 Java内存模型

    什么是内存模型 JMM(Java内存模型)规定了JVM必须遵循一组最小保证,这组保证规定了对变量的写入操作在何时将对其他线程可见. JMM为程序中所有的操作定义了一个偏序关系,称为Happens-Be ...

  9. 【java并发编程实战】第一章笔记

    1.线程安全的定义 当多个线程访问某个类时,不管允许环境采用何种调度方式或者这些线程如何交替执行,这个类都能表现出正确的行为 如果一个类既不包含任何域,也不包含任何对其他类中域的引用.则它一定是无状态 ...

  10. Java并发编程实战 第8章 线程池的使用

    合理的控制线程池的大小: 下面内容来自网络.不过跟作者说的一致.不想自己敲了.留个记录. 要想合理的配置线程池的大小,首先得分析任务的特性,可以从以下几个角度分析: 任务的性质:CPU密集型任务.IO ...

随机推荐

  1. XP IE8 安装失败

    装完XP后,此时是IE6.装了QQ浏览器,提示会锁定浏览器主页,没怎么在意. 然后装IE8时,提示失败. 在网上搜索了下是其它浏览器或程序锁定了浏览器主页.卸载QQ浏览器后,成功安装IE8.

  2. selenium 笔记 2018

    1.指定浏览器驱动:dr = webdriver.Firefox(executable_path = '/Users/xxx/Documents/selenium_py/geckodriver/gec ...

  3. PHP外部调用网站百度统计数据的方法详解

    目的:外部调用网站的百度统计(tongji.baidu.com)数据. 条件:1.具备调用目标网站的百度统计平台管理权限 2.PHP环境支持curl函数. 原理:同PHP小偷程序原理,通过curl函数 ...

  4. Docker系列06:Linux修改docker镜像和容器数据存储位置

    指定镜像和容器存放路径的参数是--graph=/var/lib/docker,其默认存储位置为/var/lib/docker, Docker 的配置文件可以设置大部分的后台进程参数,在各个操作系统中的 ...

  5. 给iOS开发新手送点福利,简述UIPageControl的属性和用法

    UIPageControl 1.   numberOfPages // 设置有多少页 默认为0 [pageControl setNumberOfPages:kImageCount]; 2.   cur ...

  6. Linux知识温习

    进程间通信(IPC)介绍 mmap - 用户空间与内核空间 linux 进程地址空间的一步步探究 mmap 还是 shmget ? linux C/C++服务器后台开发面试题总结 Trie树详解及其应 ...

  7. 常用的ubantu操作命令

    Ubuntu软件操作的相关命令 sudo apt-get update 更新源 sudo apt-get install package 安装包 sudo apt-get remove package ...

  8. 2.spring整合ehcache 注解实现查询缓存,并实现实时缓存更新或删除

    转自:http://www.importnew.com/23358.html 写在前面:上一篇博客写了spring cache和ehcache的基本介绍,个人建议先把这些最基本的知识了解了才能对今天主 ...

  9. ehlib 用法记录

    点列头排序 1.add  ehlibado.pas  to project. 2.grideh>ColumnDefValues>Title>TitleButton=true; 3.g ...

  10. XACT Q&A (转)

    XACT Q&A 传送门:http://blog.csdn.net/xoyojank/article/details/4098633