java面试之四
1、你常用的jvm监控工具或者命令有哪些
- GC日志 PrintGCDetails 每次GC记录日志
-
jstat -gcutil pid 5s 10//间隔5s,打印10次
Paste_Image.png
S0 — Heap上的 Survivor space 0 区已使用空间的百分比
S1 — Heap上的 Survivor space 1 区已使用空间的百分比
E — Heap上的 Eden space 区已使用空间的百分比
O — Heap上的 Old space 区已使用空间的百分比
M — Metaspace 区已使用空间的百分比
YGC — 从应用程序启动到采样时发生 Young GC 的次数
YGCT– 从应用程序启动到采样时 Young GC 所用的时间(单位秒)
FGC — 从应用程序启动到采样时发生 Full GC 的次数
FGCT– 从应用程序启动到采样时 Full GC 所用的时间(单位秒)
GCT — 从应用程序启动到采样时用于垃圾回收的总时间(单位秒) - jstack pid:结合top看看是不是cpu过高,导致死锁
2、java8的lambda表达式了解过吗?
java8之前:
new Thread(new Runnable(){
public void run() {
System.out.println(1123);
}
}).start();
java8:
new Thread(() -> System.out.println(123)).start();
还有其他的好多东西,下次找个时间专门研究一下这个。
3、A,B两个线程同时启动,但让A结束后B在结束,如何实现。
用join关键字。t.join()方法阻塞调用此方法的线程(calling thread),直到线程t完成,此线程再继续;通常用于在main()主线程内,等待其它线程完成再结束main()主线程。例如:
public class Test implements Runnable{
private String name;
public Test(String name) {
this.name = name;
}
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println(new Date()+" "+name);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Test("zhangsan"));
Thread thread1 = new Thread(new Test("lijia"));
thread.start();
thread1.start();
thread.join();
thread1.join();
System.out.println("qqqqqqqqqqqq");
}
}
运行结果
如果把join去掉:
Paste_Image.png4、java中什么是锁
我认为面试官一般问这种问题都是想问你synchronized。主要是问完这个也会顺带着问Lock。锁里面还有一些概念公平锁、非公平锁、自旋锁、可重入锁、偏向锁、轻量级锁、重量级锁、读写锁、互斥锁等。
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
-
修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
-
修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
-
修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
-
修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
public class Test2 { public static void main(String[] args) { SyncThread syncThread = new SyncThread(); Thread thread1 = new Thread(syncThread, "SyncThread1"); Thread thread2 = new Thread(syncThread, "SyncThread2"); thread1.start(); thread2.start(); } } class SyncThread implements Runnable { private int count; public SyncThread() { count = 0; } public void run() { // synchronized(this) { for (int i = 0; i < 5; i++) { try { System.out.println(Thread.currentThread().getName() + ":" + (count++)); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } // } } public int getCount() { return count; } }
运行结果为
加上synchronized之后
再没有加锁之前,两个线程相互调用cpu,加锁之后,SyncThread1线程执行完才到SyncThread2,而且保证了正确性。
那么再说说volatile吧
还是用上面的例子说明,其他都不动
private volatile int count;//在count这加入volatile
运行结果
图片.png 图片.png用volatile只能保证可见性,但是不保证原子性。如上图,结果就是不正确的。
volatile也能禁止重排序
那么volatile怎么保证可见性和禁止重排序
引入深入理解java虚拟机中一段话: 观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令
lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:
1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
2)它会强制将对缓存的修改操作立即写入主存;
3)如果是写操作,它会导致其他CPU中对应的缓存行无效。
使用volatile必须具备以下2个条件:
1)对变量的写操作不依赖于当前值
2)该变量没有包含在具有其他变量的不变式中
也会说道Lock和AQS,请看
http://www.jianshu.com/p/d333d5177498。
也许会问JUC下的一些其他类,这里不说了。