[编程语言]jvm角度看synchronized

参考书籍:《深入理解java虚拟机》

  • 0 jvm线程模型

  • 1 synchronized是什么?有什么用?

    synchronized是java中的关键字,表示对资源进行同步。作用是防止多个线程对共享资源同时操作时导致数据不一致。

  •  2 线程同步问题产生的根本原因是jvm内存模型

    处理器速度和内存读取速度相差太大,于是在处理器和内存中加入了高速缓存,这样一来多处理器就会造成内存数据同步的问题,内存数据同步和jvm线程数据同步类似。

在jvm中可共享的数据存放于堆和方法区,虚拟机栈在执行方法的时候要把共享数据读入到栈帧的局部变量表中,也就是共享数据的拷贝,这样会造成每个虚拟机栈中都有一份共享数据的拷贝,而且可能会导致数据不一致。

堆对应主内存,线程的虚拟机栈栈帧的局部变量表对应高速缓存这只是逻辑上的对应,并不是一个层次的划分。

主内存和工作内存之间的交互,jvm定义了4对8个原子性操作:

lock、unlock:作用于主内存的变量,将变量标识为线程独占的状态;解锁。unlock操作之前必须把变量同步会主内存中,也就是最新store、write操作

read、load:主内存变量传递到线程工作内存;将read到的值放到工作内存的变量副本。

use、assign:将变量传递给执行引擎;把执行引擎返回的值赋值给工作内存的变量副本;

store、write:将工作内存的变量副本传递到主内存;将store获得的值保存到主内存的变量。


插一段volatile的东西:

volatile的设计:(1)read到write的操作必须是一连串的动作,保证了取最新的值和立马刷新到主内存 (2)禁止指令重排序 

禁止重排序的原理:动作C之前必然发生动作A、B,动作D之后必然发生动作E、F,如果C优先于D则整个执行顺序是A-B-C-D-E-F。我认为volatile的设计本质在于:如果一个变量马上被使用但是没有被load过那样是禁止的。由于jdk1.6后对synchronized进行优化,几乎没有volatile的用处了。

happen-before原则:A操作先于B操作,那么B操作能够观察到A操作产生的影响,这些影响包括变量的改变等等。


 

  • 3 synchronized的设计思路

    2.1 synchronized汇编代码:通过javap命令看下synchronized的汇编代码,synchronized会对应生成一对monitorenter和monitorexit(看到有两个monitorexit,一个是正常退出,一个是异常退出)

package indi.wangx.java.thread;

public class SynchronizedTest {

	public static int a = 1;
	
	public void testSynchronized() {
		synchronized(this) {
			a++;
		}
	} 
}


 

2.2 jvm是如何实现monitorener和monitorexit的呢?

       jvm通过8个原子性操作中的lock和unlock进行操作。

       java.util.concurrency中的ReentrantLock在synchronized上做了3方面的优化:

(1)等待可中断 (2)公平锁:先排队的先获得锁 (3)锁定多个Condition对象

3 实现线程安全的方法

       (1)互斥同步:例如使用synchronized关键字

       (2)非阻塞同步:先进行操作共享数据,如没有其他线程使用共享数据,直接操作;如果有其他线程使用共享数据进行其他不长措施(比如不停地重试直到成功为止)

        非阻塞同步靠硬件指令完成,有一个实例可以看下,就是原子类AutomicInteger

        这段代码的核心在于不停的compareAndSet,把一个比自己大1的值设置给自己,直到能够设置成功的时候返回。

4 锁优化

        (1)锁自旋:大部分线程持有锁的时间很短,于是在线程同步互斥时不切换到等待状态,切换到等待状态需要转到内核态,这非常耗费时间,所以就让线程进行一段自旋操作。而且jdk1.6之后引入了自适应的自旋锁,自旋时间由钱一次同一个锁的自旋时间和锁的拥有者状态决定。

        (2)编译器进行锁消除:编译器把无用的锁进行消除

        (3)锁粗化和锁细化:加锁的范围太小导致重复加锁,加锁的范围太大导致不应该加锁的地方也加了锁

        (4)偏向锁:在无竞争下消除整个同步,只在第一次使用CAS操作获取锁,并在Mark Word中存储线程ID,持有偏向锁的线程每次进入这个锁相关的同步块,虚拟机不进行任何同步操作。

        (5)轻量级锁:本质上跟锁自旋是一个道理,采用CAS操操作避免了将其他线程变为等待状态。对于绝大部分的锁,整个同步周期中并没有竞争。如果有2个以上的线程轻量级锁会转变为重量级锁,Mark Word的标志位变为10。


hotspot对象头内存布局:

        1 hotspot对象头分为2部分:

        (1)对象自身运行时数据:HashCode、GC分代年龄、锁标记等,这部分称为Mark Word

        (2)存放指向方法区对象类型数据的指针

        轻量级锁加锁的过程如下图:


        jvm中的锁分为四种状态:无锁、偏向锁、轻量级锁、重量级锁,有这几种锁的原因是避免线程的阻塞和唤醒,线程的阻塞和唤醒需要切换到内核态,非常耗时

偏向锁的执行过程:本质上就是有锁但无竞争。看偏向标志,如果是"01"则表示当前为偏向模式,用CAS操作线程ID记录到Mark Word中。如果有二个线程尝试获取锁的时候,撤销偏向锁。

轻量级锁的执行过程:本质上是只有2个线程的轻度竞争,虚拟机栈栈帧建立一个Lock Record的空间,存放Mark Word的拷贝,CAS操作尝试将Mark Word更新为指向指向线程虚拟机栈栈帧的Lock Record。

如果两条以上的线程竞争一个锁就转变为重量级锁,意味着其它线程需要进行wait。

以上是jvm锁内存变化,下面这种图是对象持有的ObjectMonitor

 

5 死锁

package indi.wangx.java.thread;

import org.junit.Test;

public class DeadLockTest {
	public Object a = new Object();
	public Object b = new Object();
	
	@Test
	public void testDeadLock() {
		new Thread(new LockA()).start();
		new Thread(new LockB()).start();
		
	}
	
	public class LockA implements Runnable{
		@Override
		public void run() {
			synchronized(a) {
				System.out.println("LockA get a");
				try {
					Thread.sleep(1000*1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized(b) {
					System.out.println("LockA get b");
				}
			}
		}
		
	}
	
	public class LockB implements Runnable{

		@Override
		public void run() {
			synchronized(b) {
				System.out.println("LockB get b");
				try {
					Thread.sleep(1000*1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized(a) {
					System.out.println("LockB get a");
				}
			}
		}
		
	}
}

用jstack和jConsloe命令可以看到造成死锁的线程。

如何避免死锁?

1 如果要获取多个锁的时候,考虑获取锁的顺序,保证不会出现循环等待

2 超时放弃,用Lock接口提供的tryLock

如何确保多个线程顺序执行?

1使用join接口

2使用单个线程池

源码链接: https://pan.quark.cn/s/fa13cd6c6c8d Chrome浏览器作为一款备受青睐的网页浏览器,凭借其出色的稳定性和运行速度获得了广泛认可。 然而出于安全考量,Chrome系统默认不兼容ActiveX插件,因为ActiveX技术主要应用于Internet Explorer,它赋予网页内容用户本地系统交互的能力,但同时也可能引发潜在的安全隐患。 不过在某些特定工作场景下,比如在企业内部网络环境或需要老旧应用程序整合时,可能仍需在Chrome中启用ActiveX控件。 为此我们必须掌握在Chrome浏览器下加载和运用ActiveX的方法。 首先需要明确ActiveX的本质。 ActiveX是由微软设计的一种技术框架,旨在开发可在网页环境中运行的控件,这些控件能够完成多种功能,包括视频播放、应用程序组件运行或硬件设备通信等。 ActiveX控件多以OCX(OLE控件)格式发布。 在Chrome浏览器中启用ActiveX需要采取额外措施,因为该浏览器本身并不支持此项技术。 以下是几种常见的解决方案: 1. **应用Chrome的兼容性设置**:部分Chrome版本提供了" --enable-internal-activex"命令行参数,可通过此参数使浏览器具备加载ActiveX控件的能力。 用户可在启动Chrome时,于快捷方式的目标路径后附加该参数来激活此功能。 例如:"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --enable-internal-activex。 2. **安装第三方插件**:市面上存在一些第三方插件,例如"IE Tab"或"ActiveX Con...
标题SpringBoot微信小程序结合的健康饮食平台研究AI更换标题第1章引言介绍健康饮食平台的研究背景、意义、国内外研究现状、论文方法及创新点。1.1研究背景意义阐述健康饮食平台在当前社会的重要性及其市场需求。1.2国内外研究现状分析国内外健康饮食平台的发展现状及趋势。1.3研究方法及创新点概述本文采用的研究方法和技术创新点。第2章相关理论总结健康饮食、SpringBoot及微信小程序的相关理论。2.1健康饮食理论介绍健康饮食的基本原则和营养学知识。2.2SpringBoot框架阐述SpringBoot框架的特点、优势及在项目中的应用。2.3微信小程序技术介绍微信小程序的开发技术、特点及其用户群体。第3章健康饮食平台设计详细介绍健康饮食平台的设计方案,包括前端和后端设计。3.1平台架构设计给出平台的整体架构、模块划分及交互流程。3.2数据库设计介绍数据库的设计思路、表结构及数据关系。3.3前后端交互设计阐述前后端数据交互的方式、接口设计及安全性考虑。第4章微信小程序实现介绍微信小程序的具体实现过程,包括页面设计、功能实现等。4.1页面设计布局给出微信小程序的页面设计思路、布局及交互效果。4.2功能实现测试详细介绍微信小程序各项功能的实现过程及测试方法。4.3用户体验优化阐述如何提升微信小程序的用户体验,包括界面优化、性能优化等。第5章平台测试优化对健康饮食平台进行测试,并根据测试结果进行优化。5.1测试环境数据介绍测试环境、测试数据及测试方法。5.2测试结果分析从功能、性能、用户体验等方面对测试结果进行详细分析。5.3平台优化策略根据测试结果提出平台优化策略,包括代码优化、功能改进等。第6章结论展望总结本文的研究成果,并展望未来的研究方向。6.1研究结论概括本文的主要研究结论和平台实现效果。6.2展望指出本文研究的不足之处以及未来研究的方向和改进点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值