java知识小总结

java知识小总结

  • Java虚拟机
    • java虚拟机结构
      • 方法区
      • 垃圾回收系统
      • 本地方法栈
      • pc寄存器
      • 执行引擎
  • java内存模式
    • 规范
    • 特性
  • java的垃圾回收机制
    • 相关算法
    • 运行过程
  • 多线程
    • 线程种类
    • sychronized
    • volatile
      • 可见性保证
      • 不具备原子性
      • 对volatile的正确使用要做到
    • 悲观锁
    • 乐观锁
    • 可重复锁
  • 单例模式
    • 懒汉模式
    • 饿汉模式
  • 类加载模式
    • 过程
    • 引用:
    • 类加载器:
    • 类加载代理模式:双亲委托机制:

Java虚拟机

java虚拟机结构

  1. 堆用来储存创建好的对象和数组
  2. JVM只有一个堆,所有线程共享
  3. 堆是一个不连续的内存空间,分配灵活,速度慢

  1. 栈描述的是方法执行的内存模型,每个方法被调用都会创建一个栈帧
  2. JVM为每个线程都创建一个栈,用于存放该线程的执行方法信息
  3. 栈属于线程私有,不能实现线程间的共享
  4. 栈的特性先进后出
  5. 栈是由系统自动分配,速度快!栈是一个连续的空间

方法区

  1. JVM只有一个方法区,被所有线程共享
  2. 方法区也是堆,只是来存储类、常量相关的信息
  3. 用来存放程序中永远是不变或者唯一的内容(类信息、字符串常量、静态变量)

垃圾回收系统

垃圾回收机制会自动触发对内存,对不需要的内存进行释放

本地方法栈

本地方法的调用,JVM允许java直接调用本地方法

pc寄存器

每个线程的私有空间,jvm会为每个java线程创建pc寄存器

执行引擎

负责执行虚拟机的字节码

java内存模式

规范

  1. 线程解锁前,共享变量的值刷新回主内存
  2. 线程枷锁前,必须把主内存的最新值拷贝到自己的工作内存
  3. 加锁解锁是同一把锁

特性

1.可见性
2.原子性
3.有序性

java的垃圾回收机制

垃圾回收机制会自动触发对内存,对不需要的内存进行释放
对象分为三类:年轻代,年老代、持久代
JVM将堆分为三个空间:Eden、Survivor(2个,一个使用一个空)、Old
GC:Minor GC(清理年轻代)、 Major GC(清理老年代)、 Full GC(清理年轻代、老年代)

相关算法

  • 引用计数法:
    使用引用计数(已经淘汰了)
    当遇到双重引用的时候有出现问题。
  • 复制算法 :
    从一个区复制到另外一个区(需要双倍内存 ,效率高没有内存碎片)
  • 标记清除:
    从根节点开始扫描,对存活对象进行标记,扫描整个内存空间在进行回收未被标记的内存,(不需要额外空间 两次扫描 有内存碎片)
  • 标记压缩:
    先标记、清除未被标记的内存,并往一段移动存活对象(没有内存碎片 需要移动对象的成本)
    根节点
  1. 静态变量引用的对象
  2. 本地方法也就是Native方法引用的对象
  3. 常量变量引用的对象
    年轻代使用复制算法
    年老代使用标记清除和标记压缩整合 (产生很多碎片后再进行压缩)。

运行过程

  1. 创建对象的时候,绝大部分会放置在Eden区
  2. 当Eden满了的时候会触发Minor GC,清除掉Eden区用无用的资源,并把有用的资源拷贝到Survivor区中,并清空Eden区
  3. 当Eden又满了的时候会触发Minor GC,清除掉Eden区用无用的资源,并把有用的资源拷贝到Survivor的另外一个区中,并清空Eden区,并将另外一个Survivor区中的不可清除的资源拷贝到这个区。
  4. 重复多次没有被清除的资源(默认15次),会被拷贝到old区
  5. 到old区满了的时候会触发Full GC

多线程

创建模式

  • 继承Thread类
  • 使用Runnable接口
  • 使用callable接口//和线程池一起使用

线程种类

  • 用户线程
  • 守护线程
    守护线程 为用户线程提供服务,当用户线程全部结束后,守护线程因为没有服务对象会直接结束, 例子:虚拟机内部的GC(垃圾回收器)

sychronized

被sychronized修饰的代码块同一时间只能被一条线程访问
sychronized修饰的代码段 具有原子特性、可见性特性、有序性
sychronized

volatile

volatile被这个关键词修饰的变量具有synchronized 的可见性特性,但是不具备原子特性,volatile也有禁止指令重排的作用。

可见性保证

当对被volatile修饰的变量就行修改的时候,会讲工作空间中的数值拷贝到主存中,并且通知其他线程,该变量的值发生了改变。

不具备原子性

当多个线程对volatile修饰的变量进行自加加操作时,其结果会和应获取结果发生偏差。
对volatile修饰的变量进行自加加时,其过程是 三个部分:

  1. 将volatile修饰的变量拷贝到工作内存中
  2. 对工作内存的变量进行自加一运算
  3. 将工作内存的变量拷贝到主内存中并通知其他线程该变量的纸发生改变

在第三步通知其他其他线程中,其他线程的可能已经也在执行第三步,最终导致操作发生丢失

对volatile的正确使用要做到

  • 对变量的写操作不依赖于当前值。
  • 该变量没有包含在具有其他变量的不变式中。

解决多线程下并发问题的工具

悲观锁

只有它被释放,其它线程才可以使用
sychronized就是悲观锁

乐观锁

每次不加锁而假设没有冲突去完成操作,操作失败则重试
CAS就是一个乐观锁
CAS 全称Compare and swap

CAS是java中rt里的一个unsafe类的方法,具有原子性(CPU直接操作不会被打断)。
Compare and swap 先比较版本,版本相同再交换 (可以解决volatile的没有原子性的特点)

例子 AtomicInteger 类对象, object.decrementAndGet(),object.decrementAndGet()。
CAS缺点:

  • 循环时间可能比较长
  • 只能保证一个共享变量的原子操作
  • 可能会有ABA问题

ABA问题
指的是CAS比较版本的时候 出现了相同版本的不同时间的出现。导致整个事件中间发生发生了其它改变
解决ABA问题的方案:使用时间戳

可重复锁

可重复锁的特点:对一个线程对象已经获取某个对象的锁,再次加锁不会出现死锁
Synchronized关键词可是可重复锁,可直接使用
ReentrantLock类也是一个可重复锁
但是需要手动上锁和解锁Lock和unLock。
(Synchronized需要指定被锁的对象,ReentrantLock是被锁的对象本身)

单例模式

既一个类对外只有一个对象
特征:

  1. 私有化构造函数
  2. 提供私有静态属性 储存对象地址
  3. 提供公共的静态方法 获取属性,属性为空则创建对象

懒汉模式

  • 简单实现
private static myObject instance=new myObject ();
Public static myObject getinstance(){
     
	return instance;
}
  • 枚举单例
public enum myObject{
     
  INSTANCE;
}

饿汉模式

  • 简单实现
private static myObject instance;
Public static myObject getinstance(){
     
	If(instance==null)instance=new myObject ();
	return instance;
}
  • 多线程下的饿汉
private static myObject instance;
Public static myObject getinstance(){
     
	Synchronized(myObject .class){
     
	If(instance==null)instance=new myObject ();
	}
	return instance;
}
  • 双重检测模式(由于编译器的代码重排原因可能会出错)
private static myObject instance;
Public static myObject getinstance(){
     
	If(instance!=null)return instance;
	Synchronized(myObject .class){
     
		If(instance==null)instance=new myObject ();
	}
    return instance;
}
/*
可能出错原因:编译器代码重排导致创建实例对象的时候
instance指向不为null,而instance里的内容尚未初始化。
*/
  • volatile修饰实例的 双重检测模式
private static volatile myObject instance;
Public static myObject getinstance(){
     
	If(instance!=null)return instance;
	Synchronized(myObject .class){
     
		If(instance==null)instance=new myObject ();
	}
    return instance;
}
//避免代码重排带来的问题
  • 静态内部类
    静态私有化实例直接初始化并且放置到内部类中
    调用静态获取实例函数的时候,直接返回(静态内部类的静态变量不会直接初始化,被访问的时候才会被初始化)
Private static Sinleton{
     
private static myObject instence=new myObject();
}
Public static myObject getinstance(){
     
Return Sinleton.instance;
}

类加载模式

加载-》链接(验证,准备,解析)-》初始化

过程

  1. 加载
    将字节码加载到内存中,并且将这些静态数据转化成方法区中的运行时的数据结构,在堆里生存一个代表这个类的java.Lang.class对象,作为方法区数据的访问入口
  2. 链接:
  • 验证:确保加载的类符合JVM规范,没有安全方面的问题
  • 准备:正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配
  • 解析:虚拟机常量池内的符号引用替换为直接引用
  1. 初始化
    执行类构造器,类构造器会收集类内所有静态成员以及对类静态成员赋值的语句合并而成。初始化一个类的时候,会先初始化父类。虚拟机会保证一个类的类构造器被加锁和同步。

引用:

  • 类的主动引用(发生类的初始化):
  1. 创建一个对象,使用类的静态方法和静态成员(除了final常量)
  2. 进行反射调用,
  3. 程序入口所在的类
  4. 被调用类的父类
  • 类的被动引用(不发生类的初始化):
  1. 引用类的常量,
  2. 类数组定义引用,
  3. 引用常量(编译阶段就被加入常量池)

类加载器:

java运行时环境的一部分,负责将java类动态的加载jvm的内存空间中(按需加载)

  • 启动类加载器(C++实现,没有父类)
  • 拓展加载器(java语言实现,父类加载器为NULL)
  • 应用程序类加载器(java语言实现,,父类加载器为拓展类加载器)
  • 自定义类加载器(父类加载器为 应用程序加载器)

类加载代理模式:双亲委托机制:

双亲委托机制要求除顶层类加载器外,其余的加载器都应有自己的父类加载器。
双亲委托机制中的父子关系并非继承,二手采用组合关系来复用父类加载器的相关代码。

先检查是否装载,如果已经装载则直接返回。
委托类加载到父类,父类能够完成则返回父类加载器加载的Class实例。

你可能感兴趣的:(java)