面试造火箭,工作拧螺丝。相信所有的朋友面试都会被问到特别底层的东西,问到你怀疑人生,而工作中完全用不到,为什么呢?
我认为原因有三:
-
岗位竞争激烈
随着这个行业人才饱和,入门门槛越来越高,与其招你进来都是拧螺丝,那我还不如看看能不能招到造火箭的呢
-
挖掘潜力
拧螺丝永远是拧螺丝的,对技术的掌握程度决定了你在公司以后能走到什么样的位置
-
对技术的追求
对于一种技术,你只是会用,而没有去深度挖掘,说明你对技术没有那么热爱,那么公司也不会放心让你去工作。
互联网三高是哪三高?
- 高血压
- 高血脂
- 高血糖
开个玩笑~
- 高可用
- 高性能(高并发、低延迟)
- 高扩展
volitile的作用
保持线程可见性
先来看个小程序
private static boolean running = true;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
while (running) {
}
System.out.println("end...");
}).start();
Thread.sleep(1000);
running = false;
}
这个程序有个静态变量,默认是true,启动一个线程,里面有个循环,只要running为true就会一直while循环,然后下面我sleep1秒,running的值改为false,这时候程序会输出end…吗?
你会发现,程序1s后依然在运行,没有输出end…,为什么?我明明已经给running赋值为false了。
因为JVM里,你的静态变量在主内存里初始化值为true,当你new一个线程的时候,会把主内存的这个值拿到线程私有内存中存起来,每次都会读线程本地的这个值,不会去主内存中同步新的值,就算你有其他的线程把主内存的值改成false了,你读到的依然是本地的值,所以程序是不会输出end…的。
这个时候我在running上加个volatile
关键字,再看下结果
private static volatile boolean running = true;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
while (running) {
}
System.out.println("end...");
}, "server").start();
Thread.sleep(1000);
running = false;
}
程序在1s后输出了end…,说明了什么?volatile关键字修饰的是主内存中的running,它的作用是保持线程可见性,它会让这个线程每次都从主内存中取值。
禁止指令重排序
什么叫指令重排序?CPU的效率要比内存的效率高100倍,假如有一个CPU和一块内存,CPU有两条指令要执行,第一条 x+1
,第二条 y+1
,这两条指令互不相关,以前CPU执行的时候是按顺序执行的,等指令一执行完以后再执行指令二,而内存的效率又非常慢,这就导致CPU的效率发挥不到极致,所以CPU就做了优化,既然是两条互不影响的指令,那我为什么非要等指令一执行完再去执行指令二呢,我也可以先执行指令二,再执行指令一,这样就会整体提升效率,这就是指令重排序。
比如你想喝茶,你需要先洗水壶–>烧开水–>洗茶壶–>洗茶叶–>拿茶杯–>泡茶–>喝茶,指令重排序就是在你烧开水的过程之中,我把洗茶壶、洗茶杯、拿茶杯的事全干了,效率就提升了。
在JVM中有8种情况是不允许指令重排序的,这是JVM的规定。比如必须先new一个对象然后才可以GC。
怎么证明指令重排序的存在?
private static int x = 0, y = 0;
private static int a = 0, b = 0;
public static void main(String[] args) throws InterruptedException {
int i = 0;
while (true) {
i++;
x = 0; y = 0;
a = 0; b = 0;
Thread one = new Thread(()->{
a = 1;
x = b;
});
Thread other = new Thread(()->{
b = 1;
y = a;
});
one.start();
other.start();
one.join();
other.join();
String result = "第"+i+"次("+x+","+y+")";
if (x == 0 && y == 0) {
System.out.println(result);
break;
}
}
}
这个程序就能证明指令重排序真的存在,这是一个死循环,里面有4个变量,两个线程分别对它们赋值,如果指令重排序不存在,那么先写的先执行,后写的后执行,x和y不可能同时等于0,只有同时执行第二句才可能出现x=0,y=0。
那volatile是如何禁止指令重排序的呢?
下篇文章说一下美团的一个面试题,**DCL到底需不需要volatile?**这篇文章会解释volatile是如何禁止指令重排序的。