【读书笔记】《Java并发编程实战》第三章 对象的共享_并发编程实战 建模的简单性_孤丨焰的博客-程序员秘密

技术标签: 读书笔记  java  # Java并发编程实战笔记  多线程  

可见性

 在多线程编程中,通常,我们无法确保读操作的线程能实时的看到其他线程写入的值。
 为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。

 并发编程过程中可能会发生“重排序”等问题,如例1

//例1
public class NoVisibility {
    
	private static boolean ready;
	private static int number;
	
	private static class ReaderThread extends Thread {
    
		public void run() {
    
			while (!ready) {
    
				Thread.yield();
			}
			System.out.println(number);
		}
	}

	public static void main(String[] args) {
    
		new ReaderThread().start();
		number = 42;
		ready = true;
	}
}

 Novisibility可能会持续循环下去,因为读线程可能永远都看不到ready的值。另一种情况,NoVisibility可能会输出0,因为读线程可能看到了写入ready的值,但却没有看到之后写入number的值。这种现象被称为“重排序”。

失效数据

 在缺乏同步的程序中可能产生错误的一种情况:失效数据。当读线程查看ready变量时,可能会得到一个已经失效的值。除非每次访问变量时都使用同步,否则很可能得该变量的一个失效值。

非原子的64位操作

 非volatile类型的64位数值变量(doublelong)。Java内存模型要求,变量得到读取操作和写入操作都必须是原子操作,但对于非volatile类型的long和double变量,JVM允许将64位的读操作或写操作分解为两个32位的操作。当读取一个非volatile类型的long变量时,如果对该变量的读操作和写操作在不同线程中执行,那么很可能会读取到某个值得高32位和另一个值得低32位。

加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步。

Volatile变量

 这里还需要说明下volatile关键字的作用,可以说有2个作用,其一是,用volatile修饰的变量的读取和写入都是直接操作内存,以保证被其它线程读取到值都是最新的,或者称之为确保内存的可见性;其二是,保证变量的读取和写入操作都是原子操作,就是上面long和double的读取所遇到的问题,注意这里提到的原子性只是针对变量的读取和写入,并不包括对变量的复杂操作,比如i++就无法使用volatile来确保这个操作是原子操作。

使用volatile的需要满足的所有条件:

a、对变量的写入操作不依赖于变量当前的值,或者你能确保只有单个线程更新变量的值

b、该变量不会与其他状态变量一起纳入不变性条件中

c、在访问变量时不需要加锁

发布与逸出

 “发布”一个对象的意思是指,使对象能够在当前作用域之外的代码中使用。
 “逸出”是指某个不应该发布的对象被发布。

 当“发布”一个对象时,在该对象的非私有域中引用的所有对象同样会被发布。

以下示范一个错误案例:
 当ThisEscape发布EventListener时,也隐含地发布了ThisEscape实例本身,因为在这个内部类的实例中包含了对ThisEscape实例的隐含引用。

public class ThisEscape{
    
	source.registerListener(new EventListener() {
    
		public void onEvent(Event e) {
    
			doSomething(e);
		}
	});
}

不要在构过程中使this引用逸出。

 在构造过程中使this引用逸出的一个常见错误是,在构造函数中启动一个线程。在构造函数中创建线程并没有错误,但最好不要立即启动它。
 在构造函数中调用一个可改写的实例方法时,同样也会导致this引用在构造过程中逸出。
 如果想在构造函数中注册一个事件监听器或启动线程,那么可以使用一个私有的构造函数和一个公有的工厂方法,从而避免不正确的构造过程。

线程封闭

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

ThreadLocal类

 维持线程封闭性的一种规范方法是使用ThreadLocal,这个类能使线程中某个值与保存值的对象关联起来。ThreadLocal提供了get与set等访问接口或方法,这些方法为每个使用该变量的线程都存有一份独立的副本。

ThreadLocal对象通常用于防止可变的单实例变量或全局变量进行共享。

不变性

不可变对象举例:

//不可变对象
public final class ThreeStooges {
    
	private final Set<String> stooges = new HashSet<>();

	public ThreeStooges() {
    
		stooges.add("Moe");
		stooges.add("Larry");
		stooges.add("Curly");
	}

	public boolean isStooge(String name) {
    
		return stooges.contains(name);
	}
}

不可变对象一定是线程安全的。

 当满足一下条件时,对象才是不可变的:
 a、对象创建以后其状态就不能修改。
 b、对象的所有域都是final类型。
 c、对象时正确创建的(在对象创建期间,this引用没有逸出)。

安全发布

 发布不可变对象的引用时没有使用同步,也仍然可以访问该对象。
可变对象必须通过安全的方式来发布。这意味着发布和使用该对象的线程时都必须使用同步。可变对象必须通过安全的方式来发布,并且必须是线程安全的或者由某个锁保护起来。

要安全地发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见。
一个正确构造的对象可以通过以下方式来安全地发布:
a、在静态初始化函数中初始化一个对象引用。
b、将对象的引用保存到volatile类型的域或者AtomicReferance对象中。
c、将对象的引用保存到某个正确构造对象的final类型域中。
d、将对象的引用保存到一个由锁保护的域中。

思维导图总结

在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Handsome_Le_le/article/details/107233887

智能推荐

使用DeepWalk从图中提取特征_喜欢打酱油的老鸟的博客-程序员秘密

2019-12-03 15:05:14目录数据的图示 不同类型的基于图的特征 节点属性 局部结构特征 节点嵌入 DeepWalk简介 在Python中实施DeepWalk以查找相似的Wikipedia页面数据的图示当你想到“网络”时,会想到什么?通常是诸如社交网络,互联网,已连接的IoT设备,铁路网络或电信网络之类的事物。在图论中,这些网络称为图。网络是互连节点的集合。...

java-基础之getParameterMap接收前端提交的表单数据_getparameter获取表单数据_一一一57的博客-程序员秘密

//接受注册form表单数据Map&lt;String, String[]&gt; map = request.getParameterMap();//封装User对象User user = new User(); try { //BeanUtils工具类的一个方法,该方法将map中的数据映射到JavaBean中的get和set方法中(封装数据到JavaBean中)。 //之后取值就直接从JavaBean中的get和set方法中取值就可以了 BeanUtils.pop

Chrome打开浏览器弹出网页、浏览器被劫持解决方法_chrome自动弹出网页_zollty的博客-程序员秘密

Chrome等浏览器,打开浏览器弹出网页、浏览器被劫持通常有如下几种情况,对照检查:1、找到浏览器“快捷方式”的文件位置,然后右键打开,选择“属性”:查看“目标”,看看exe后面还有没有跟其他字符串,有的话删除。2、注册表,运行regedit打开,然后找到计算机\HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main右边项目中找到Start Page,看它的值是否正常。3、Chrome浏览器,菜单栏.

团队的英文翻译缩写_公司的部门英文缩写简称大全1_weixin_39553904的博客-程序员秘密

精彩文档BOMBillOfMaterial物料清單PSPackageSpecification包裝規範SPECSpecification規格DWGDrawing圖面部類PMCProduction&amp;MaterialControl生產和物料控制PPCProductionPlanControl生產計劃控制MCMaterialControl物料控制MEManufactureEngineering製...

php pdo sqlserver驱动,centos mssql pdo驱动及配置_weixin_39552768的博客-程序员秘密

centos下安装freeTDS 安装unixODBC 编译php_pdo_odbc模块 编译php_mssql模块 编译php_pdo_dblib模块首先了解一下PDO的一些基本知识:PDO是PHPDateObject的简称,它是PHP 5.1版本一起发行的,目前支持的数据库包括Firebird,FressTDS,MySQL,Ms SQL Server,ODBC,Oracle等。有了PDO,您不...

该死的错误,http500--java.lang.reflect.InvocationTargetException_lhxiong的博客-程序员秘密

HTTP Status 500 - type Exception reportmessage description The server encountered an internal error () that prevented it from fulfilling this request.exception java.lang.reflect.Invocation

随便推点

Spring系列(一):Spring是如何加载Bean的?_哟哟之名的博客-程序员秘密

一、Spring容器有哪些?单例池:是一个concurrentHashMap,key是beanName,value是objectBeanFactoryApplicationContext:是BeanFactory的一种拓展AnotationConfigApplicationContext(不可刷新):以注解方式ClassPathXMLApplicationContext(可刷新):从项目的根路径开始查找文件FileSystemXMLApplicationContext(可刷新):从工程的根路径

输出层的几种激活函数_输出层激活函数_vectorindex的博客-程序员秘密

1.恒等函数:按照原样进行输出,对输出的信息不加以任何的改动 2.softmax激活函数 :适用于多分类问题,输出属于各个分类的概率 (因为输出层softmax全部相加=1,正是因为这个原因,把softmax解释为概率) 3.sigmoid激活函数:适用于二分类,单个输出为0到1间的概率,所以他看的并不是输出的整体。关于2,3的理解:输出(0, 1)代表“是”,输出(1, 0)代表“否”Softmax可能输出(0.3, 0.7),代表算法认为“是”的概率是0.7,“否”...

4.RuntimeError(“{} is a zip archive (did you mean to use torch.jit.load()?)“.format(f.name))_图形学挖掘机的博客-程序员秘密

问题在pytorch-gpu10.0 即cuda10.0的pytorch虚拟环境中(torch1.2.0)运行VoronoiNet代码时候,会出现上面的错误,一开始我以为是因为学姐的代码对pytorch版本有要求,但是问了学姐那里的torch版本就是1.2.0的,就很奇怪为什么我这里明明是相同的环境怎么就不行,有bug。在网上查找原因,发现基本都是说torch版本的问题 →????使用torch.load()加载模型参数时,提示“xxx.pt is a zip archive(did you mea

从PRISM开始学WPF(五)MVVM(一)ViewModel?_weixin_30568715的博客-程序员秘密

从PRISM开始学WPF(五)MVVM(一)ViewModel? 原文:从PRISM开始学WPF(五)MVVM(一)ViewModel?从PRISM开始学WPF(一)WPF?从PRISM开始学WPF(二)Prism?从PRISM开始学WPF(三)Prism-Region?从PRISM开始学WPF(四)Prism-Module?从...

【容器】Docker之django+mysql简单部署示例_eponia的博客-程序员秘密

拓扑:1. 在CentOS7上,django项目目录为/smb/public/eclipse-workspace/DjangoProj/djcode/mysite, 映射到容器django中的目录为/tmp2. 在CentOS7上,mysql数据库对应的目录为/var/lib/docker/volumes/mysql,映射到容器mysql中的目录为/var/lib/mysql步

Flink 1.11.1:table sql支持cdc debezium数据源下的Interval Join_TracyGao01的博客-程序员秘密

Flink:1.11.1目的Flink SQL CDC 模式输出的Json类型数据不支持 Interval Join,由于Interval Join只支持 append-only 的表,所以这里需要修改CDC模式debezium组件的输出格式,适配支持Table Interval Join实现这里我们通过新增一个format的形式来适配Interval Join,取名为’insert-debezium-json’,这里需要新建两个class文件如下:DebeziumJsonDeserizat.

推荐文章

热门文章

相关标签