大公司不仅仅要求你会使用几个api,更多的是要你熟悉源码实现原理,甚至要你知道有哪些不足,怎么改进,还有一些java有关的一些算法,设计模式等等。
1.描述的是方法执行的内存模型。每个方法被调用都会创建一个栈帧(栈里的元素:局部变量,操作数,方法出口等等)
2.jvm为每个线程创建一个栈,用于存放该线程执行方法的信息
3.栈是线程私有的,不能线程间共享
4.先进后出
5.栈有系统自动分配,速度快,内存空间连续
1.堆是用来存放创建好的对象和数组
2.jvm只有一个堆,被所有线程共享
3.内存空间不连续,速度慢
方法区也是堆
1.jvm只有一个方法区,被所有线程共享
2.方法区实际上也是堆,只是用于存放类,常量
3.用于存放程序中永远不变/唯一的内容(类信息,静态变量,字符串常量等等)
需要被回收处理的是对象,所以gc是操作堆的。
堆细分为新生代,老生代,持久代(方法区)。
基本类型,判断值是否相同
引用类型,判断地址是否相同
判断对象内容是否相同
与实现类属于父子关系,提供规范
实现类继承抽象类,但是java的类是单继承(接口是多继承),继承了抽象类就无法继承其他类了。有一定局限性。
与实现类属于实现关系,提供比抽象类更规范的规范
实现类实现抽象类,可以多实现,更方便使用。
没有顺序,不可重复
有顺序,可以重复
帮助我们建立类型安全的集合。本质就是数据类型的参数化。
数组:查询快,增加删除慢
链表:查询慢,增加删除快
hashmap把2者优点结合起来了
操作系统分配资源的单位
每个进程有独立的代码和数据空间(程序上下文)
进程间切换开销大
cpu调度和执行的单位
每个线程共享所属的进程的资源
每个线程有独立的运行栈和程序计数器
线程间切换开销小
多个线程同时操作其共享的一份资源就会有并发问题,需要进行并发控制。
没有进行并发控制的操作称为线程不安全操作。
常用的HashMap是线程不安全的,对于的有线程安全的ConcurrentHashMap。
如使用同步锁(synchronized),一份资源只能同时只有一个线程可以掌控,未掌控的只能等待。
使用同步锁会有死锁问题,如A等待B中的资源,B等待A中的资源。
注:JUC就是java.util.concurrent工具包的简称,这是一个处理线程的工具包。
单cpu设置多线程是否有意义?
有。在阻塞时(如网络请求),可以提高cpu的利用率
新生,就绪,运行,阻塞,死亡
创建线程对象,就进入新生状态
调用start(),进入就绪状态,说明可以被cpu调度
被cpu调度到,进入运行状态,这时线程才开始执行代码
遇到阻塞事件进入阻塞状态
sleep,wait,join(其它线程插队),yeild(主动让出线程)
代码执行完毕
锁的是传入的对象
非静态方法锁this。
静态方法锁xxxx.class,
jvm里只会存在一个xxxx.class对象实例,
所以锁了xxxx的静态方法,
无论new出了几个对象都会被锁住。
相当于多个对象持有同一把锁。
(区别于锁非静态方法,一个对象一把锁)
它能够使变量在值发生改变时能尽快地让其他线程知道。
没有原子性
加载字节码文件,并放入方法区中,在堆中生成一个该类的java.lang.Class对象
链接到jvm运行状态中
初始化,调用类构造器(由编译器收集类的静态变量和静态代码块组成的方法)。如果初始化当前类时发现父类没有初始化就先初始化父类。
双亲委派机制,先让父加载器加载。为了安全,防止覆盖加载核心包的类
加载java核心库(jre/lib/rt.jar),
同时加载扩展类加载器和应用程序类加载器
由c++实现。
加载扩展库(jre/lib/ext/*.jar)
加载classpath下的java应用
继承java.lang.ClassLoader
队列式同步器java.util.concurrent.locks.AbstractQueuedSynchronizer
很重要
juc中几个重要的锁(可重入锁,读写锁)包括ThreadPoolExecutor都是依赖这个实现的
thread调用acquire()
会先调用tryAcquire()
尝试获取资源(判断state是否=0(ReentrantLock,在!=0,即有线程占用资源时,会判断是否是相同线程,来实现可重入)),获取到了(将state设置为1)就继续执行,没获取到就进入等待队列,并中断线程,直到正在执行的线程调用release()
释放资源(将state设置为0)。release()
会获取队列(先进先出)头的线程,唤醒(有2中模式,公平模式:唤醒最先进入队列的线程;不公平模式:唤醒所有等待线程,看谁能抢到资源)这个线程。
new 对象,无锁。
偏向锁,在markword位置存放当前线程指针(贴个标签)
轻量级锁,有不同的线程开始要竞争这个对象,先把偏向锁取消了,然后每个线程在自己的线程栈中生成一个lock record对象,谁先把lr的指针放入markword中,就算抢到了锁。
重量级锁,如果竞争加剧,升级重量级锁(向操作系统申请)。因为轻量级锁(自旋锁)死循环会消耗cpu,
1.java代码:synchonized 2.字节码:monitorenter monitorexit 3.jvm:自动升级锁 4.汇编:lock comxchg
cpu缓存块(缓存行)64字节 如果2个不相干的变量在同一个缓存行里,使用volatile会通知另外线程中的缓存行,效率变慢, 对齐使2个变量在不同的缓存行里,不用通知。
jvm:内存屏障
该对象比较大时可以使用,内存空间充足,一直存在,内存空间不足会被删除。
只要垃圾回收器执行,就会被回收。 ThreadLocal
获取不到,管理堆外内存用 如nio中的DirectByteBuffer,使用的是堆外内存,当这个引用不需要时,gc回收这个对象时,把引用放入队列中,由专门的堆外内存gc回收。