这两种对象访问方式各有优势。使用句柄来访问的最大好处是reference中存储的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而reference本身不需要修改。使用直接指针访问方式最大的好处就是速度快,它节省了一次指针定位的时间开销。
Minor GC 的触发条件:Eden区域没有足够的空间。
Full GC(Major GC)的触发条件:老年代没有足够空间。
Java中的引用类型
强引用(new):只要强引用还存在,垃圾收集器就不会回收被引用的对象。
软引用(SoftReference):在系统将要发生内存溢出异常之前,将会把这些对象列入回收范围进行二次回收。
弱引用(WeakReference):只能存活到下次垃圾收集发生之前。
虚引用(PhantomReference):一个对象是否有虚引用存在,不对其生存时间构成影响。
拯救对象:可以用finalize()方法拯救一次对象。
Java堆分为新生代和老年代,默认比例为新生代:老年代 = 1:2,即新生代占总堆内存的1/3,老年代占2/3。
jps的功能类似于Linux的ps命令,可以列出正在运行的虚拟机进程, 并显示虚拟机执行主类名称,以及这些进程的本地虚拟机唯一ID(LVMID)。
jps [options] [hostid]
options:
-l 输出主类全名,如果执行的是jar包则输出jar路径
-v 输出虚拟机进程启动时JVM参数
hostid:开启了RMI服务的远程虚拟机主机名
jstat用于监视虚拟机的各种运行状态信息,包括类装载、垃圾收集以及运行期编译状况等。
jstat [ option vmid [ interval[s|ms] [count] ] ]
interval与count代表查询间隔和次数
vmid是虚拟机进程ID
option:
-gc:监视Java堆状况,包括容量、已用空间以及GC信息等
-gcutil:与gc选项基本相同,但关注点主要是已使用空间占总空间的百分比
jinfo的作用是实时查看和调整虚拟机各项参数。
jinfo [option] pid
加载、连接(验证、准备、解析)、初始化、使用、卸载
java.lang.Class
对象作为方法区这个类的各种数据的访问入口。()
方法。类加载器在层次上由上至下(由父至子)分别为:
%JAVA_HOME%\lib
目录下的类库。%JAVA_HOME%\lib\ext
目录下的类库。双亲委派模型:若一个类加载器收到类加载请求,它首先不会尝试自己加载这个类,而是把这个请求委托给它的父加载器去完成,每一层次类加载器都是如此,只有当父类加载无法加载时,子加载器才会尝试自己加载。
破坏双亲委派机制:自定义类加载器,重写loadClass()方法
进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。
线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
线程创建之后处于NEW(新建)状态,调用start()方法后线程处于READY(可运行)状态。可运行状态的线程获得CPU时间片后就处于RUNNING(运行)状态。当线程执行wait()方法之后,线程进入WAITING(等待)状态,进入等待状态的线程需要依靠其他线程的通知才能够返回到READY状态。sleep(long millis)或wait(long millis)方法会让线程变为TIMED_WAITING状态,TIME_WAITING(超时等待) 在等待状态的基础上增加了超时限制,当超时时间到达后Java线程将会返回到REDAY状态。当线程调用同步方法时,在没有获取到锁的情况下,线程将会进入到BLOCKED(阻塞)状态。线程在执行完的run()方法之后将会进入到TERMINATED(终止)状态。
什么是死锁:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。
产生死锁的四个必要条件:
如何避免死锁:破坏请求与保持条件(一次性申请所有的资源)、破坏不剥夺条件(占用部分资源的线程进一步申请其他资源时,如果申请不到主动释放它占有的资源)、破坏循环等待条件(按某一顺序申请资源,释放资源则反序释放)。
wait()与sleep()区别: sleep方法没有释放锁,而wait方法释放了锁 。
start()与run():调用start()方法,会启动一个线程并使其进入就绪状态,当分配到时间片后就可以自动执行run()方法的内容,这是真正的多线程工作。 而直接执行run()方法,会把run方法当成一个main线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程。
synchronized关键字解决的是多个线程之间访问资源的同步性,synchronized关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。
synchronized实现单例模式:
public class Singleton {
//volatile禁止指令重排序
private volatile static Singleton instance;
private Singleton() {
}
public static Singleton getSingleton() {
//先判断对象是否已经实例过,没有实例化过才进入加锁代码
if (instance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
synchronized同步语句块实现原理:
synchronized同步语句块使用的是monitorenter和monitorexit指令,执行monitorenter指令时,线程试图获取monitor(monitor对象存在于每个Java对象的对象头中,因此Java中任意对象可以作为锁) 锁的持有权。当计数器为0,则可以成功获取,获取后将锁的计数器设为1。执行monitorexit指令时,将锁计数器设为0,表明锁被释放。如果获取对象锁失败,那么当前线程就要阻塞等待,直到锁被另外一个线程释放为止。
锁优化(偏向锁、轻量级锁、自旋锁、适应性自旋锁、锁消除、锁粗化):