继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Java同步—并发三大性质

慕容森
关注TA
已关注
手记 239
粉丝 182
获赞 648

Java并发三大性质

在Java内存模型中,有三大性质:原子性有序性可见性.

原子性:即一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其它线程干扰.

有序性:即程序执行的顺序按照代码的先后顺序执行.

可见性:当多个线程访问同一个变量的时候,一旦线程修改了这个变量的值,其他线程能够李可看到修改的值。

原子性

举个例子:A想要从自己的帐户中转1000块钱到B的帐户里。那个从A开始转帐,到转帐结束的这一个过程,称之为一个事务.在这个事务里,要做如下操作:

  1. 从A的帐户中减去1000块钱。如果A的帐户原来有3000块钱,现在就变成2000块钱了。

  2. 在B的帐户里加1000块钱。如果B的帐户如果原来有2000块钱,现在则变成3000块钱了。

如果在A的帐户已经减去了1000块钱的时候,忽然发生了意外,比如停电什么的,导致转帐事务意外终止了,而此时B的帐户里还没有增加1000块钱。那么,我们称这个操作失败了,要进行回滚。

我们把这种要么一起成功,要么一起失败的操作叫原子性操作。

如果把一个事务可看作是一个程序,它要么完整的被执行,要么完全不执行.这种特性就叫原子性

举一个精确的例子:

int x = 1; 
int y = x;  
x++;
x += 1;

以上四句代码,一眼看去都是原子性操作,其实里面只有第1句是原子性操作.

首先我们来了解下计算机的工作方式:

在我们运行程序的时候,CPU会执行程序的每条指令,在执行程序的过程中,肯定会涉及到一些临时数据,这些数据是存放在内存中的。这就存在一个问题,CPU执行指令的速度比从内存中读取数据和向内存中写入数据快很多.如果任何时候操作数据都要从内存中读写的话,会大大降低程序的运行速度,因此就有了高速缓存:

在程序运行过程中,会将运算需要的数据从内存复制一份到CPU的高速缓存中,当CPU计算的时候,就可以直接从它的高速缓存中读写数据。结束运算后,再将高速缓存中的数据写入内存中。

我们再回来看一下刚才的四句代码:

int x=1;//给x赋值为1,这个操作会直接将10写入内存中
int y=x;//这其实是两个操作,先读取x的值,然后将x的值赋值给y再写入内存中,这两个操作虽然都是原子性操作,但是合起来就不是原子性操作了
x++;
x+=1;//这两句代码包含3个操作,先去读取x的值,然后进行加1,在把新值写入到内存中

但是注意一个问题,第一句代码:

int x=1;//假设x是一个32位的变量,那为它赋值包含两个过程,给低16位赋值,给高16位赋值,所以也不是原子性操作

可见性

对于可见性,Java提供了volatile关键字来保证可见性。

当一个共享变量被volatile修饰的时候,他会保证对值的修改,会立刻被其他共享的线程看见,从而下次加载的时候会从内存中重新取值,而不是从高速缓存中取值,但是volatile变量不能保证原子性。

如果想保证原子性,可以使用synchronizedReentrantLock,他们既可以保证可见性,也可以保证原子性,但是开销会大很多。

有序性

在Java中,允许编译器和处理器对指令进行重排序,什么叫重排序,说简单点就是改变指令的执行顺序。重新排序不会影响单线程执行,却会影响到多线程并发执行。

同样,可以使用synchronizedReentrantLock,他们也会保证有序性

但是,我们今天讲点额外的东西,Java内存模型中具有一些先天的有序性。也称为happens-before原则。

happens-before原则:

  • 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作

  • 锁定规则:一个unLock操作先行发生于后面对同一个锁的lock操作

  • volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作

  • 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C

  • 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作

  • 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生

  • 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行

  • 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始

转自:https://www.cnblogs.com/dolphin0520/p/3920373.html


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP