00jvm

JVM原理(java虚拟机)

1.jvm内存

在Java中,“线程”指两件不同的事情:
1、java.lang.Thread类的一个实例;
2、线程的执行。
使用java.lang.Thread类或者java.lang.Runnable接口编写代码来定义、实例化和启动新线程。
一个Thread类实例只是一个对象,像Java中的任何其他对象一样,具有变量和方法,生死于堆上。
Java中,每个线程都有一个调用栈,即使不在程序中创建任何新的线程,线程也在后台运行着。
一个Java应用总是从main()方法开始运行,mian()方法运行在一个线程内,它被称为主线程。
一旦创建一个新的线程,就产生一个新的调用栈。
线程总体分两类:用户线程和守候线程。
当所有用户线程执行完毕的时候,JVM自动关闭。但是守候线程却不独立于JVM,守候线程一般是由操作系统或者用户自己创建的
在这里插入图片描述

1.类变量(类里面static修饰的变量) 保存在“方法区” 线程共享数据区
2.实例变量(类里面的普通变量)保存在“堆” 线程共享数据区
3.局部变量(方法里声明的变量)保存在 “虚拟机栈” 线程私有数据区

因此,局部变量是不能多个线程共享的,而类变量和实例变量是可以多个线程共享的。
事实上,在java中,多线程间进行通信的唯一途径就是通过类变量和实例变量。
一段多线程程序中如果没有类变量和实例变量,就是没有线程共享数据区,那么这段多线程程序就一定是线程安全的。

其实多线程根本的问题只有一个:线程间变量的共享,
这里的变量,指的就是类变量和实例变量,后续的一切,都是为了解决类变量和实例变量共享的安全问题。

1.2安全的共享变量

有一个类变量a=0,现在启动5个线程,每个线程执行a++;

1.ThreadLocal的方式,其实这种方式并不是真正的共享,而是为每个线程分配一个自己的值,结果就是5个线程都拥有一份自己的a值,最终结果都是1。
2.直接声明一个类变量a=0(类里面static修饰的变量) 保存在“方法区” 线程共享数据区,然后让5个线程分别去执行a++;这样结果依旧不对,而且结果是不确定的,可能是1,2,3,4,5中的任一个。这种情况叫做竞态条件(Race Condition)。

解决方法:
每个java线程都有一份自己的工作内存,线程访问变量的时候,不能直接访问主内存中的变量,而是先把主内存的变量复制到自己的工作内存,然后操作自己工作内存里的变量,最后再同步给主内存。
在这里插入图片描述

为什么5个线程执行a++最后结果不一定是5了,因为a++可以分解为3步操作:
1.把主内存里的a复制到线程的工作内存
2.线程对工作内存里的a执行a=a+1
3.把线程工作内存里的a同步回主内存
5个线程并发执行的时候完全有可能5个线程都先执行了第一步,这样5个线程的工作内存里a的初始值都是0,
然后执行a=a+1后在工作内存里的运算结果都是1,最后同步回主内存的值肯定也是1。

避免这种情况的方法就是:在多个线程并发访问a的时候,保证a在同一个时刻只被一个线程使用。

同步(synchronized)就是:在多个线程并发访问共享数据的时候,保证共享数据在同一个时刻只被一个线程使用。

为了保证共享数据在同一时刻只被一个线程使用,我们有一种很简单的实现思想,就是在共享数据里保存一个锁,
当没有线程访问时,锁是空的,当有第一个线程访问时,就在锁里保存这个线程的标识并允许这个线程访问共享数据。
在当前线程释放共享数据之前,如果再有其他线程想要访问共享数据,就要等待锁释放。

1.3jvm的同步实现

jvm中的三种锁都是以上述思想为基础的,只是实现的“重量级”不同,jvm中有以下三种锁(由上到下越来越“重量级”):
1.偏向锁
2.轻量级锁
3.重量级锁

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值