面试准备-java【2】

7 篇文章 0 订阅

编译执行,解释执行
解释执行:代码仅仅编译成class文件,没有转化为机器码,虚拟机读取一行代码,转化成一行机器码,然后执行。
编译执行:代码完全编译成机器码,直接交由机器执行。

jvm虚拟机是混合模式,大部分是解释执行,但是对部分热点代码会JIT(just-in-time)编译器,也是我们常说的动态编译器,编译成机器码,此处是编译执行。

运行模式可以通过jvm参数来指定。不同平台有不同的解释器,这是java可以跨平台的基础,同时只要符合字节码规则,其他例如Scala、Groovy语言也可以在jvm平台上运行。

NoClassDefFoundError和ClassNotFoundException的不同
1)NoClassDefFoundError是error,ClassNotFoundException是可检查异常
2)NoClassDefFoundError是链接错误,编译时正常能找到类,相当于有一个指向具体类的链接,但是运行时找不到类。可能原因是编译完成之后,jar包删除了,或者存在多个版本的jar包
3)ClassNotFoundException,发生在运行时,一般出现在显式使用Class.forName()、ClassLoader.findSystemClass()和ClassLoader.loadClass()等方法加载类时。

举一个不恰当的例子:
NoClassDefFoundError:通过地图导航,明明有一条路径可以到达目的地(编译,链接),但是实际去走的时候,发现某一段是死路(无jar包),无法走下去,或者存在两个名字相同的店铺,只是老板不一样(版本冲突
ClassNotFoundException:边走边找(运行中),路人告诉你现在应该直走过十字路口(显式调用类加载),但是前面明明是个丁字路口,没办法直走

参考链接:https://www.jianshu.com/p/93d0db07d2e3

Throwable是异常的基类,Error和Exception是子类
Error 是指在正常情况下,不大可能出现的情况,绝大部分的的 Error 都会导致程序(比如 JVM 自身)处于非正常的、不可恢复状态。
Exception可以分为检查,不可检查,区别是编译器是否可以检查出来,比如IO异常是检查异常,不可检查异常一般是代码逻辑错误,编译器无法发现,运行时发生,比如空指针,数组越界等。

BIO,NIO,AIO
BIO:io包中传统的InputStream/OutputStream,Reader/Writer,同步阻塞IO
NIO:同步非阻塞IO
在这里插入图片描述
个人认为:channel是输入输出流的一种抽象,可以转化为对应的流,往channel中写数据是通过对应数据类型的buffer。selector是以个集合,容器,用于存储channel,所谓就绪状态就是channel注册到selector时候的状态参数,每个channel关注的不同状态。因为是单线程轮训,channel的相对顺序是固定的,同时也比BIO的多线程轮询,切换的开销更小。获取到channel之后是在单线程中执行还是分发到线程池执行,可以根据业务不同来选择

AIO(nio2):异步非阻塞IO,基于事件和回调机制,简单理解为,应用操作直接返回,不会阻塞在那里,当后台处理完成,操作系统会通知相应线程进行后续工作。

同步:可靠有序的运行机制,执行顺序是有序的
异步:执行顺序不定,依靠事件、回调等机制控制次序
阻塞IO:线程处于阻塞状态,只有相关条件就绪,例如socket建立,文件输入输出完成后才能继续执行。
非阻塞IO:不管IO操作是否结束直接返回,相应操作在后台继续执行。

NIO常用类:selector,channel,buffer
常用属性:capacity,position和limit
常用方法:flip,rewind,clear/compact,mark/reset。scatter/gather,transferFrom/transferTo

死锁
死锁条件:互斥资源;长期持有,结束之前不会释放,也不会被抢占;循环依赖
检查工具:jstack;java标准api,ThreadMXBean
分析过程:区分线程状态->查找等待资源的目标->对比Monitor等持有状态,确定循环依赖关系
尽量减少死锁的策略:尽量在确实需要时才获取锁,减少在一个操作里获取多个锁;获取锁可以加上超时时间,超时退出逻辑,并释放锁;参考银行家算法,安排好获取锁的获取释放顺序,尽可能保证不会出现死锁情况;
线程状态

ReadWriteLock读写之间互斥吗
除了读/读之间不是互斥的,读/写,写/写之间都是互斥的,因为读的时候也要获取锁,开销也是比较大的,所以有一个单独的StampedLock,读之间可以通过tryOptimisticRead或者readLock获得一个“版本号”,获取读的数据之后,通过validate方法判断版本号,确定数据是否被改变过,就是一个CAS的操作

http://ifeve.com/jdk8%E4%B8%ADstampedlock%E5%8E%9F%E7%90%86%E6%8E%A2%E7%A9%B6/
StampedLock 和ReentrantReadWriteLock区别

  • ReentrantReadWriteLock 可重入,即同一个线程可以多次获取锁,释放的时候也要多次释放,两个lock的读锁都是非独占的区别不大,主要在获取写锁的时候,stampedLock不可重入意味着同一个线程获取写锁会被阻塞
  • stampedLock的写锁和悲观读锁和ReentrantReadWriteLock中的读写锁类似,是采用CAS的方式,且读/写互斥,会被阻塞
  • stampedLock多了一种乐观读,返回stamp,需要调用方在数据更新时判断数据是否已经被改动,是否升级成悲观读锁。乐观读没有采用CAS真正获取锁,所以允许一个线程获取写锁,而ReentrantReadWriteLock的只有读锁,所有写都会被阻塞,所以针对读多写少的情况,stampedLock性能更好
    其余可参考Java并发 – StampedLock

Semaphore拿到执行权的线程之间是否互斥
Semaphore可有多把锁,可允许多个线程同时拥有执行权,这些有执行权的线程如并发访问同一对象,会产生线程安全问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值