jvm相关
-
内存模型
- 主内存和本地私有内存,每次更新数据时,本地私有内存会从主内存中拉取数据,然后在将修改后的数据更新到主内存实现内存刷新
-
内存划分
- 元空间使用本地内存,永久代使用jvm内存,在1.8之后常量池存放在堆中,堆中分为年轻代和老年代
https://github.com/Snailclimb/JavaGuide/blob/master/Java相关/可能是把Java内存区域讲的最清楚的一篇文章.md
https://github.com/Snailclimb/JavaGuide/blob/master/Java相关/可能是把Java内存区域讲的最清楚的一篇文章.md -
内存区域
- 栈内存
在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配,当超过变量的作用域后,java会自动释放掉为该变量所分配的内存空间 - 堆内存
堆内存用来存放由new创建的对象和数组以及对象的实例变量,在函数(代码块)中定义一个变量时,java就在栈中为这个变量分配内存空间,在堆中分配的内存由java虚拟机的自动垃圾回收器来管理
java变量存储区域 https://blog.csdn.net/happy_zzzhao/article/details/78876009
- 栈内存
-
内存分配策略
- 栈有2种方式
静态存储:在编译过程时,会分配所需内存空间
动态存储:在启动入口时,分配内存空间 - 堆有一种方式
动态存储:在程序运行过程中动态分配内存空间
堆内存分为年轻代和老年代
- 栈有2种方式
-
内存管理
Java的内存管理就是对象的分配和释放问题。(两部分)- 分配:
内存的分配是由程序完成的,程序员需要通过关键字new 为每个对象申请内存空间 (基本类型除外),所有的对象都在堆 (Heap)中分配空间。 - 释放:
对象的释放是由垃圾回收机制决定和执行的,这样做确实简化了程序员的工作。但同时,它也加重了JVM的工作。因为,GC为了能够正确释放对象,
GC必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都需要进行监控。
- 分配:
-
栈与堆的区别
- 栈的内存释放在变量超过作用域时会自动释放内存空间,堆由gc来进行自动回收,采用隔代回收算法
- 栈资源消耗比堆少
- 栈的速度要比堆快
堆优势:
可以动态分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的。堆缺点:
在运行时动态分配内存,存取速度较慢; 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。 -
调整堆栈的内存大小
- -xss: 每个线程虚拟机堆栈大小
- -xms: 堆初始化大小
- -xmx: 堆最大内存容量
-
Java类加载双亲委派机制
- custom classloader appclassloader excisionclassloader bootstrap classloader
- 尝试加载顺序 从顶部到底部 检查类是否已加载顺序 从底部到顶部
-
GC相关
- 年轻代采用了复制算法,老年代采用标记-清除算法
- gc回收算法-引用计数法 实例对象有引用的时候个数+1,置为空时个数-1,如果引用个数为0时会被gc进行回收
-
虚拟机垃圾收集器
- java中的gc在调用期间是不会立刻生效的,只会作标记待下次gc线程扫描到此标记才会进行回收,回收的时间不确定
- 关于对象回收
1.强引用:一般是通过new对象产生的,只有当对象置为null,才可能被回收掉,时间不确定
2.软引用:softReference 只有当内存不足时,才会被回收,时间不确定,适合做高速缓存
3.弱引用:随时可能被回收
java框架
-
java集合框架
- ConcurrentHashMap
- 在JDK1.7的时候,ConcurrentHashMap(分段锁)对整个桶数组进行了分割段(Segment),每一把锁只锁容器其中一部分数据,
多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。(默认分配16个Segment,比Hashtable效率提高16倍。) - 到了 JDK1.8 的时候已经摒弃了Segment的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作。
(JDK1.6以后 对 synchronized锁做了很多优化)
-
java8
- hashMap:相比于之前的版本,JDK1.8之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。
多线程
进程与线程的区别
进程:一个可执行的应用程序,进程之间互不影响,各个进程都是独立的
线程:进程的中一个可执行的任务,同一个进程中的线程会存在资源共享问题,线程之间会受到影响
三大特性
原子性:数据同步保证一致
可见性:java内存模型
有序性:线程之间的通信
sleep和wait区别
sleep:线程会让出cpu资源并释放锁,当sleep结束后会重新开始竞争cpu调度资源
wait:线程不会让出cpu资源同时也不会释放锁,只有notify才会唤醒线程
notify和notifyAll区别
notify:只会随机唤醒一个线程
notifyAll: 会唤醒所有等待线程
synchronized和lock区别以及volatile和synchronized的区别
1.synchronized在发生异常时可以释放锁,lock是接口,lock在发生异常时,只能通过finally手动释放锁,lock可以判断是否成功获取锁
2.volatile用来修饰变量,用来保证多个线程之间变量的可见性,不会发生阻塞,synchronized修饰方法、代码块,用来解决多个线程
之间资源共享问题,会发生阻塞
多线程是解决什么问题的
处理并发任务,提高程序执行效率,但是需要考虑线程之间资源共享问题
线程池解决什么问题
有效管理线程 减少性能损耗频繁创建线程关闭线程
线程池的原理
线程池中会保存新创建的线程,当线程池中数量堆满时,会开启最大线程池,用来存放线程,当线程数超过最大线程池数时,会进入阻塞队列
线程池会利用已创建的线程进行复用
thread与runable关系
- thread是一个类,runnable是一个接口,thread也实现了runable
如何获取线程返回结果
- 实现callable接口,线程使用futureTask,调用get方法获取返回结果
run方法与start区别
- run方法是调用当前方法线程执行
- start是调用jvm新创建一个线程执行
线程的六个状态
- 新建 运行 无限期等待(调用无时间限制的sleep、wait) 限期等待 阻塞 结束
volatile
- 可见性:变量使用volitail修饰后,线程对变量进行写操作时,会将本地私有内存刷新到主内存中,读变量时会销毁当前线程中本地私有内存,读取主内存变量值
- 内存屏障:在每个线程操作变量时,会在操作指令前后进行内存屏障,防止当前操作重新排序
创建线程池参数
- corePoolSize 核心线程数
- maximumPoolSize 最大线程数
- keepAliveTime 闲置的线程最长等待新任务时间
- queue 任务等待队列
- ThreadFactory 创建线程时使用的线程工厂
线程池的几种创建方式
- newFixedThreadPool 创建指定大小的线程池
- newScheduledThreadPool 定时任务线程
- newCachedThreadPool 缓冲型线程池:初始核心线程数为0,线程个数为最大,默认闲置时间为60秒
- newSingleThreadExecutor 单例线程池,只会在线程池中创建一个线程,只有当前线程结束时才会再次创建线程
线程池的运行流程
首先会进入线程队列中,创建线程后会进入线程池,如果达到最大线程数时,线程就会处于线程队列中进行等待
,当线程池中线程结束时,会从线程队列中获取新的线程进入线程池
- 提交任务
- 判断线程数是否小于核心线程数,创建工作线程
- 判断阻塞队列是否没满,添加任务到阻塞队列中
- 判断线程数是否小于最大线程数,添加工作线程并执行
CAS原理(乐观锁方式)
线程在操作变量时,会生成三个标识 V 内存原值 A 要修改的内存原值 B 新值,在线程要更新变量时,会先判断预期修改的内存值A是否等于内存原值A,如果相等,才会把新值赋值给V