Java内存模型与线程(三)

时间记录:202-2-2
上章节主要了解volatile的使用和一些细节部分操作,下面主要为long和double变量的一些特殊规则,还有就是java内存模型的一些特性吧。

long和double变量的一些特殊操作

long和double都是64位的,在java虚拟机中有一条宽松的规定:允许虚拟机将没有被volatile修饰的64位数据的读写操作划分为两次32位操作来进行。之前说到对变量的操作的原子性,这样的情况即是允许虚拟机实现选择可以不保证64位数据类型的load,store,read和write着四个操作的原子性,这个就是非原子性协定,那么在多线程读取的情况下就可能会读取到一个半值,这个目前我没碰到过出现这种情况,大部分都认为其实原子的。注意下这个问题就可以了,以后如果遇到要想起。

java内存模型的特性

之前已经了解java内存模型中的变量的访问规则,然后其主要是围绕的原子性可见性有序性来建立的。

一:原子性
由java内存模型直接保证的原子性变量操作包括read,load,assign,use,store,write,我们大致可以认为基本数据类型的访问读写是具备原子性的(double,long除外,但是这种基本上不会发生的情况,我们不去考虑了)。我们常说的原子操作,就是说一个操作过程中是独立的,不会受到外面的干扰,在java中也提供了字节指令monitorentermonitorexit,对应的就是java中我们常用的synchronized,可以尝试下将代码块转成指令就会发现在一头一尾存在这个指令了。

二:可见性
指的是当一个线程修改了共享变量的值后,其余线程是立即得知这个修改的。java内存模型是通过在变量的值修改后将值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方式来实现可见性的,可以主要是内存的访问方式限制的。而普通变量也是这样,但是普通变量不能立即同步回去,而volatile变量是可以的,而且保证了每次在使用前都是从主内存刷新的新值,从而保证了多线程操作的时候变量的可见性。
除了volatile还有synchronizedfinal
synchronized是由于对变量执行unlock操作前必须将此变量同步回主内存中。
final是在构造器中一旦初始化完成,并且构造器没有this的引用传递出去(这里指的是完全初始化才被传递出去,这里可能出现的是this的引用逃逸,即是指没有被完全初始化就被放出去了,然后其他线程看到的就是不完整的内容,所以当前的值就可能没有),那么在其他线程中就能看到final的值
this引用逃逸案例
this引用逃逸的主要的内容就是时候在构造函数没有完全执行时将此引用抛出,而其它线程此时是可见的,导致了值没有被初始化,所以导致了问题,这个现象被称为this引用逃逸。

package com.huo.mem;

public class ThisEscape 
{
	final int a = 0;
	int b = 0;
	
	static ThisEscape thisEscape;
	
	public ThisEscape() 
	{
		b =1;
	}
	
	public static void main(String[] args) 
	{
		Thread thread1 = new Thread(new Runnable() {
			
			@Override
			public void run() 
			{
				thisEscape = new ThisEscape();
			}
		});
		
		Thread thread2 = new Thread(new Runnable() {
			
			@Override
			public void run() 
			{
				ThisEscape temp = thisEscape;
				System.out.println(temp.a+"  "+temp.b);
			}
		});
		
		thread1.start();
		thread2.start();
	}
}

结果:

Exception in thread "Thread-1" java.lang.NullPointerException
	at com.huo.mem.ThisEscape$2.run(ThisEscape.java:32)
	at java.lang.Thread.run(Thread.java:745)

或者

0  1

主要原因就是在未被初始化完成就使用了导致了这个问题。

三:有序性
如果在本线程观察所有的操作都是有序的;如果在一个线程中观察另一个线程,所有的操作都是无需的。前部分来说是线程内表现为串行语义,后半部分就是指令重排工作内存和主内存同步延迟。有序性就是程序运行的正确顺序,我是这样觉得。
在java中提供了volatilesynchronized保证了线程间的有序性,也就是对应后半部分内容。
volatile本省就包含了禁止指令重排的语义,而synchronized是由一个变量只能由一个线程来对其进行lock操作,前章节提及的变量的操作规则相对应。

时间记录:2020-2-2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值