JMM&volatile(二)

线程的生命状态

在这里插入图片描述

为什么用到并发

  • 充分利用到多核cpu 的计算能力
  • 方便业务的拆分 , 提升应用性能

  • 并发的会产生问题
  1. 高并发的场景下 , 导致频繁的上下文切换
  2. 临界区的安全问题 , 容易产生死锁
  • 线程的上下文切换
    在这里插入图片描述

在这里插入图片描述

  1. 线程执行时经时间片的轮转 , 当线程A 未执行完毕就开始执行线程B时 , 讲线程的的执行信息保存在Tss任务状态段 ,
  2. 在时间片的轮转后 , 开始执行线程A , 冲TSS任务段读取线程A的指令, 程序指令、中间数据 到cpu寄存器缓存中 , 开始正式执行线程A

在这里插入图片描述

java 内存区域逻辑图

在这里插入图片描述

java 内存模型内存交互操作

在这里插入图片描述
JMM-同步八种操作介绍(1)

  • lock(锁定):作用于主内存的变量,把一个变量标记为一条线程独占状态
  • (2)unlock(解锁):作用于主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
  • (3)read(读取):作用于主内存的变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用
  • (4)load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中
  • (5)use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎
  • (6)assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量
  • (7)store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作
  • (8)write(写入):作用于工作内存的变量,它把store操作从工作内存中的一个变量的值传送到主内存的变量中

如果要把一个变量从主内存中复制到工作内存中,就需要按顺序地执行read和load操作,如果把变量从工作内存中同步到主内存中,就需要按顺序地执行store和write操作。但Java内存模型只要求上述操作必须按顺序执行,而没有保证必须是连续执行

在这里插入图片描述
同步规则分析1)

  1. 不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步回主内存中
  2. 一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或者assign)的变量。即就是对一个变量实施use和store操作之前,必须先自行assign和load操作。
  3. 一个变量在同一时刻只允许一条线程对其进行lock操作,但lock操作可以被同一线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。lock和unlock必须成对出现。
  4. 如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量之前需要重新执行load或assign操作初始化变量的值。
  5. 如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。
  6. 对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)

Volatile在这里插入图片描述

voaltiel的内存语义

  • 是java虚拟机提供的轻量级的同步机制有一下两个作用
  1. 保证volatile修饰的共享变量对所有线程可见(当其中的一个线程修改共享变量值 , 新值可以被其他线程立刻得知)
  2. 禁止指令重新排列优化

volitile 的可见性

  • 被volatile修饰的变量对所有线程总数立即可见的,对volatile变量的所有写操作总是能立刻反应到其他线程中
publicclassVolatileVisibilitySample {
				volatile  boolean  initFlag = false;
		publicvoidsave(){
				this.initFlag = true;
				String threadname = Thread.currentThread().getName();
				System.out.println("线程:"+threadname+":修改共享变量initFlag");}
				public    void    load(){
							String threadname = Thread.currentThread().getName();
							while(!initFlag){
							//线程在此处空跑,等待initFlag状态改变}System.out.println("线程:"+threadname+"当前线程嗅探到initFlag的状态的改变");
				}
				publicstaticvoidmain(String[] args){
				VolatileVisibilitySample sample = newVolatileVisibilitySample();
				Thread threadA = newThread(()->{sample.save();},"threadA");
				Thread threadB = newThread(()->{sample.load();},"threadB");
				threadB.start();
				try{Thread.sleep(1000);}
				 catch(InterruptedException e) {
					 e.printStackTrace();
				 }threadA.start();
				 }}

线程A改变initFlag属性之后,线程B马上感知到	
  • volatile 无法保证原子性
public	class	Volatile	Visibility {
		public  static  volatile  inti =0;
		public static  void  increase(){
		i++;}
}

在并发的场景下 , i 的变量任何改变会立刻反应到其他线程 , 但当多个线程同时调用increate()时 , 线程出现安全问题
i++ 不具备原子性 , (i 是先取值 ,再写一个回值,两步完成)(会出现的问题):

问题 : 若第二个线程于第一个线程 同时read i 的旧值 , 并同时执行 i++ , 会造成线程安全失败
解决 : ,因此对于increase方法必须使用synchronized修饰 , 以此确保线程安全 , 由于synchronized本身也具备与volatile相同的特性 , 所以可以省略volatile 的修饰变量


在这里插入图片描述

在这里插入图片描述

指令重排

发生在编译器 ,或者是机器码的时候
条件:逻辑上 感知不到指令重排会造成的影响()

  • volatile关键字另一个作用就是禁止指令重排优化,从而避免多线程环境下程序出现乱序执行的现象

实现禁止指令重排于内存屏障

  • 内存屏障
  1. 写内存屏障(Store Memory Barrier):处理器将存储缓存值写回主存(阻塞方式)。
  2. 读内存屏障(Load Memory Barrier):处理器,处理失效队列(阻塞方式)。
public    class	DoubleCheckLock {
		private	static	DoubleCheckLock	instance;
		private	DoubleCheckLock(){}
		public		static		DoubleCheckLock getInstance(){
		//第一次检测
		if(instance==null){//同步					       			
		synchronized(DoubleCheckLock.class){
			if(instance == null){//多线程环境下可能会出现问题的地方		 
			instance = newDoubleCheckLock();
}}}
		returninstance;}}
  • 当代码在多线程下执行时可能会产生的问题

在正常的情况下,代码的执行顺序

  1.    memory = allocate();    // , 分配内存空间
    
  2.    instance(memory);		// 初始化对象
    
  3.    instance  =  memory;    // 设置instance指向的内存地址 , 此时instance != null
    

可能会导致的情况:重排序

  1. memory = allocate()   ;   // 1 。 分配空间
    
  2. instance = memory;  //  3. 设置instance 指向的刚分配的地址 , 此刻 , instance  并未初始化  
    
  3. instance(memory)    //2.   初始化对象
    
  • 步骤二和步骤三不存在数据依赖的关系 , 重排前还是重排后程序的执行结果在单线程中并没有改变,因此这种重排优化是允许的 , 但是指令重排只会保证串行语义的执行的一致性(单线程),但并不会关心多线程间的语义一致性

     // 禁止指令重排privatevolatilestaticDoubleCheckLock instance
    

博客地址

内容概要:该研究通过在黑龙江省某示范村进行24小时实地测试,比较了燃煤炉具与自动/手动进料生物质炉具的污染物排放特征。结果显示,生物质炉具相比燃煤炉具显著降低了PM2.5、CO和SO2的排放(自动进料分别降低41.2%、54.3%、40.0%;手动进料降低35.3%、22.1%、20.0%),但NOx排放未降低甚至有所增加。研究还发现,经济性和便利性是影响生物质炉具推广的重要因素。该研究不仅提供了实际排放数据支持,还通过Python代码详细复现了排放特征比较、减排效果计算和结果可视化,进一步探讨了燃料性质、动态排放特征、碳平衡计算以及政策建议。 适合人群:从事环境科学研究的学者、政府环保部门工作人员、能源政策制定者、关注农村能源转型的社会人士。 使用场景及目标:①评估生物质炉具在农村地区的推广潜力;②为政策制定者提供科学依据,优化补贴政策;③帮助研究人员深入了解生物质炉具的排放特征和技术改进方向;④为企业研发更高效的生物质炉具提供参考。 其他说明:该研究通过大量数据分析和模拟,揭示了生物质炉具在实际应用中的优点和挑战,特别是NOx排放增加的问题。研究还提出了多项具体的技术改进方向和政策建议,如优化进料方式、提高热效率、建设本地颗粒厂等,为生物质炉具的广泛推广提供了可行路径。此外,研究还开发了一个智能政策建议生成系统,可以根据不同地区的特征定制化生成政策建议,为农村能源转型提供了有力支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值