Skip to content

Latest commit

 

History

History
204 lines (141 loc) · 7.21 KB

README.md

File metadata and controls

204 lines (141 loc) · 7.21 KB

学习java

大公司不仅仅要求你会使用几个api,更多的是要你熟悉源码实现原理,甚至要你知道有哪些不足,怎么改进,还有一些java有关的一些算法,设计模式等等。

java虚拟机的内存分3个区域:堆,栈,方法区。

栈:

1.描述的是方法执行的内存模型。每个方法被调用都会创建一个栈帧(栈里的元素:局部变量,操作数,方法出口等等)
2.jvm为每个线程创建一个栈,用于存放该线程执行方法的信息
3.栈是线程私有的,不能线程间共享
4.先进后出
5.栈有系统自动分配,速度快,内存空间连续

堆:

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

方法区:

方法区也是堆
1.jvm只有一个方法区,被所有线程共享
2.方法区实际上也是堆,只是用于存放类,常量
3.用于存放程序中永远不变/唯一的内容(类信息,静态变量,字符串常量等等)

gc

需要被回收处理的是对象,所以gc是操作堆的。
堆细分为新生代,老生代,持久代(方法区)。

== & equals

==

基本类型,判断值是否相同
引用类型,判断地址是否相同

equals

判断对象内容是否相同

抽象类,接口

抽象类

与实现类属于父子关系,提供规范
实现类继承抽象类,但是java的类是单继承(接口是多继承),继承了抽象类就无法继承其他类了。有一定局限性。

接口

与实现类属于实现关系,提供比抽象类更规范的规范
实现类实现抽象类,可以多实现,更方便使用。

容器Collection,Map(键值对)

Set

没有顺序,不可重复

List

有顺序,可以重复

范型

帮助我们建立类型安全的集合。本质就是数据类型的参数化。

hashmap

数组:查询快,增加删除慢
链表:查询慢,增加删除快
hashmap把2者优点结合起来了

多线程

进程

操作系统分配资源的单位
每个进程有独立的代码和数据空间(程序上下文)
进程间切换开销大

线程

cpu调度和执行的单位
每个线程共享所属的进程的资源
每个线程有独立的运行栈和程序计数器
线程间切换开销小

多个线程同时操作其共享的一份资源就会有并发问题,需要进行并发控制。
没有进行并发控制的操作称为线程不安全操作。
常用的HashMap是线程不安全的,对于的有线程安全的ConcurrentHashMap。

如使用同步锁(synchronized),一份资源只能同时只有一个线程可以掌控,未掌控的只能等待。
使用同步锁会有死锁问题,如A等待B中的资源,B等待A中的资源。

注:JUC就是java.util.concurrent工具包的简称,这是一个处理线程的工具包。

单cpu设置多线程是否有意义?

有。在阻塞时(如网络请求),可以提高cpu的利用率

线程状态

新生,就绪,运行,阻塞,死亡

新生状态

创建线程对象,就进入新生状态

就绪状态

调用start(),进入就绪状态,说明可以被cpu调度

运行状态

被cpu调度到,进入运行状态,这时线程才开始执行代码

阻塞状态

遇到阻塞事件进入阻塞状态
sleep,wait,join(其它线程插队),yeild(主动让出线程)

死亡状态

代码执行完毕

线程池

线程同步

synchronized

synchronized代码块
锁的是传入的对象
synchronized方法
非静态方法锁this。
静态方法锁xxxx.class,
    jvm里只会存在一个xxxx.class对象实例,
    所以锁了xxxx的静态方法,
    无论new出了几个对象都会被锁住。
    相当于多个对象持有同一把锁。
    (区别于锁非静态方法,一个对象一把锁)

volatile

它能够使变量在值发生改变时能尽快地让其他线程知道。
没有原子性

jvm

类加载全过程

加载字节码文件,并放入方法区中,在堆中生成一个该类的java.lang.Class对象
链接到jvm运行状态中
初始化,调用类构造器(由编译器收集类的静态变量和静态代码块组成的方法)。如果初始化当前类时发现父类没有初始化就先初始化父类。

类加载器

双亲委派机制,先让父加载器加载。为了安全,防止覆盖加载核心包的类

引导类加载器

加载java核心库(jre/lib/rt.jar),
同时加载扩展类加载器和应用程序类加载器
由c++实现。

扩展类加载器

加载扩展库(jre/lib/ext/*.jar)

应用程序类加载器

加载classpath下的java应用

自定义类加载器

继承java.lang.ClassLoader

juc

AbstractQueuedSynchronizer

队列式同步器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,

synchonized实现过程

1.java代码:synchonized 2.字节码:monitorenter monitorexit 3.jvm:自动升级锁 4.汇编:lock comxchg

缓存行对齐

cpu缓存块(缓存行)64字节 如果2个不相干的变量在同一个缓存行里,使用volatile会通知另外线程中的缓存行,效率变慢, 对齐使2个变量在不同的缓存行里,不用通知。

volatile防止指令重排序

jvm:内存屏障

强软弱虚引用

软引用

该对象比较大时可以使用,内存空间充足,一直存在,内存空间不足会被删除。

弱引用

只要垃圾回收器执行,就会被回收。 ThreadLocal

虚引用

获取不到,管理堆外内存用 如nio中的DirectByteBuffer,使用的是堆外内存,当这个引用不需要时,gc回收这个对象时,把引用放入队列中,由专门的堆外内存gc回收。