
课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
Java虚拟机的学习与应用是每一位Java程序员都应该熟练掌握的一个编程知识点,而本文我们就通过案例分析来简单了解一下,Happens-Before规则概念与应用分析。
JMM本质上包含了一些规则,那这个规则就是大家有所耳闻的Happens-Before规则,大家都理解了些规则吗?
Happens-Before规则,可以简单理解为如果想要A线程发生在B线程前面,也就是B线程能够看到A线程,需要遵循6个原则。如果不符合happens-before规则,JMM并不能保证一个线程的可见性和有序性。
1.程序的顺序性规则
在一个线程中,逻辑上书写在前面的操作先行发生于书写在后面的操作。
这个规则很好理解,同一个线程中他们是用的同一个工作缓存,是可见的,并且多个操作之间有先后依赖关系,则不允许对这些操作进行重排序。
2.volatile变量规则
指对一个volatile变量的写操作,Happens-Before于后续对这个volatile变量的读操作。
怎么理解呢?比如线程A对volatile变量进行写操作,那么线程B读取这个volatile变量是可见的,就是说能够读取到新的值。
3.传递性
这条规则是指如果AHappens-BeforeB,且BHappens-BeforeC,那么AHappens-BeforeC。
这个规则也比较容易理解,不展开讨论了。
锁的规则
这条规则是指对一个锁的解锁Happens-Before于后续对这个锁的加锁,这里的锁要是同一把锁,而且用synchronized或者ReentrantLock都可以。
5.线程start()规则
主线程A启动子线程B后,子线程B能够看到主线程在启动子线程B前的操作。
这个规则也很容易理解,线程A调用线程B的start()方法(即在线程A中启动线程B),那么该start()操作Happens-Before于线程B中的任意操作。
6.线程join()规则
线程A中,调用线程B的join()并成功返回,那么线程B中的任意操作Happens-Before于该join()操作的返回。
使用JMM规则
我们现在已经基本讲清楚了JAVA内存模型规范,以及里面关键的Happens-Before规则,那有啥用呢?回到前言的问题中,我们是不是可以使用目前学到的关于JMM的知识去解决这个问题。
方案一:使用volatile
根据JMM的2条规则,主线程写了volatile修饰的run变量,后面的t线程读取的时候就可以看到了。
方案二:使用锁
利用synchronized锁的规则,主线程释放锁,那么后续t线程加锁就可以看到之前的内容了。
小结:
volatile关键字
保证可见性
不保证原子性
保证有序性(禁止指令重排)
volatile修饰的变量进行读操作与普通变量几乎没什么差别,但是写操作相对慢一些,因为需要在本地代码中插入很多内存屏障来保证指令不会发生乱序执行,但是开销比锁要小。volatile的性能远比加锁要好。
synchronized关键字
保证可见性
不保证原子性
保证有序性
加了锁之后,只能有一个线程获得到了锁,获得不到锁的线程就要阻塞,所以同一时间只有一个线程执行,相当于单线程,由于数据依赖性的存在,单线程的指令重排是没有问题的。
线程加锁前,将清空工作内存中共享变量的值,使用共享变量时需要从主内存中重新读取新的值;线程解锁前,必须把共享变量的新值刷新到主内存中。
【免责声明】:本内容转载于网络,转载目的在于传递信息。文章内容为作者个人意见,本平台对文中陈述、观点保持中立,不对所包含内容的准确性、可靠性与完整性提供形式地保证。请读者仅作参考。更多内容请加danei456学习了解。欢迎关注“达内在线”参与分销,赚更多好礼。