技术标签: 读书笔记 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变量时,可能会得到一个已经失效的值。除非每次访问变量时都使用同步,否则很可能得该变量的一个失效值。
非volatile类型的64位数值变量(double和long)。Java内存模型要求,变量得到读取操作和写入操作都必须是原子操作,但对于非volatile类型的long和double变量,JVM允许将64位的读操作或写操作分解为两个32位的操作。当读取一个非volatile类型的long变量时,如果对该变量的读操作和写操作在不同线程中执行,那么很可能会读取到某个值得高32位和另一个值得低32位。
加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步。
这里还需要说明下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提供了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、将对象的引用保存到一个由锁保护的域中。
2019-12-03 15:05:14目录数据的图示 不同类型的基于图的特征 节点属性 局部结构特征 节点嵌入 DeepWalk简介 在Python中实施DeepWalk以查找相似的Wikipedia页面数据的图示当你想到“网络”时,会想到什么?通常是诸如社交网络,互联网,已连接的IoT设备,铁路网络或电信网络之类的事物。在图论中,这些网络称为图。网络是互连节点的集合。...
//接受注册form表单数据Map<String, String[]> map = request.getParameterMap();//封装User对象User user = new User(); try { //BeanUtils工具类的一个方法,该方法将map中的数据映射到JavaBean中的get和set方法中(封装数据到JavaBean中)。 //之后取值就直接从JavaBean中的get和set方法中取值就可以了 BeanUtils.pop
Chrome等浏览器,打开浏览器弹出网页、浏览器被劫持通常有如下几种情况,对照检查:1、找到浏览器“快捷方式”的文件位置,然后右键打开,选择“属性”:查看“目标”,看看exe后面还有没有跟其他字符串,有的话删除。2、注册表,运行regedit打开,然后找到计算机\HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main右边项目中找到Start Page,看它的值是否正常。3、Chrome浏览器,菜单栏.
精彩文档BOMBillOfMaterial物料清單PSPackageSpecification包裝規範SPECSpecification規格DWGDrawing圖面部類PMCProduction&MaterialControl生產和物料控制PPCProductionPlanControl生產計劃控制MCMaterialControl物料控制MEManufactureEngineering製...
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,您不...
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容器有哪些?单例池:是一个concurrentHashMap,key是beanName,value是objectBeanFactoryApplicationContext:是BeanFactory的一种拓展AnotationConfigApplicationContext(不可刷新):以注解方式ClassPathXMLApplicationContext(可刷新):从项目的根路径开始查找文件FileSystemXMLApplicationContext(可刷新):从工程的根路径
1.恒等函数:按照原样进行输出,对输出的信息不加以任何的改动 2.softmax激活函数 :适用于多分类问题,输出属于各个分类的概率 (因为输出层softmax全部相加=1,正是因为这个原因,把softmax解释为概率) 3.sigmoid激活函数:适用于二分类,单个输出为0到1间的概率,所以他看的并不是输出的整体。关于2,3的理解:输出(0, 1)代表“是”,输出(1, 0)代表“否”Softmax可能输出(0.3, 0.7),代表算法认为“是”的概率是0.7,“否”...
问题在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? 原文:从PRISM开始学WPF(五)MVVM(一)ViewModel?从PRISM开始学WPF(一)WPF?从PRISM开始学WPF(二)Prism?从PRISM开始学WPF(三)Prism-Region?从PRISM开始学WPF(四)Prism-Module?从...
拓扑: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目的Flink SQL CDC 模式输出的Json类型数据不支持 Interval Join,由于Interval Join只支持 append-only 的表,所以这里需要修改CDC模式debezium组件的输出格式,适配支持Table Interval Join实现这里我们通过新增一个format的形式来适配Interval Join,取名为’insert-debezium-json’,这里需要新建两个class文件如下:DebeziumJsonDeserizat.