引言
最近好久没有遇到技术瓶颈了,思考得自然少了,每天都是重复性的工作。
阿里开始招实习,同学问我要不要去申请阿里的实习,我说不去,个人对阿里的印象不好。
记得去年阿里给我发了邮件,我很认真地回复,然后他不理我了。(最起码的尊重都没有,就算我菜你起码回复我一下啊?)
这种不尊重人的公司感觉去了也不快乐,当程序员最重要的就是快乐,不快乐写什么代码?
电话面
同学很友好地分享了他的阿里电话面经验。
问的都是看功底的问题,和开发经验无关(估计写上个几年代码不写框架应该也不知道这个)。
Java
中的HashMap
、transient
、volatile
、HTTP301/302
、生产者消费者算法。
HashMap
都问烂了,问的是HashMap
的底层原理,我知道你们自己写过JDK
,请不要再问我HashMap
里的put
操作是怎么实现的了!
问源码的真的很讨厌,有什么意义吗?看过的就能答上,没看过的就答不上。
基础学习
transient
这并不是第一次听到transient
这个词了,之前也用过,当我们使用YunzhiService
进行综合查询时,我们会在实体中构造不映射到数据表的属性用于查询。
对于这些不映射为数据表字段的属性,我们使用@Transient
注解。
那Java
中被transient
修饰又是什么意思呢?
为什么要有transient
?StackOverflow
的解释通俗易懂。
The transient keyword in Java is used to indicate that a field should not be part of the serialization (which means saved, like to a file) process.
Java
中的transient
关键字,意味着该字段不参与序列化,意味着不被保存,例如输出到文件中。
序列化?fastjson
应该用到了这个关键字。
厉害厉害,fastjson
开发团队基本功扎实。
volatile
这个关键字也不知道怎么能给大家通俗的讲出来,还是从实际的小例子出发吧?
大家回忆一下我们之前的单例模式,单例模式很常用,这个是必须要会的。
这是有问题的懒汉模式,多线程的时候就不能保持单例了。
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
修正之前的问题
纠正一下之前博客中的一个问题,之前这样写虽然也能实现,但是效率极低,因为每次getInstance
的时候都会被synchronized
阻塞。
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
为了效率,不能在方法上加锁,所以需要在新建单例的时候加锁,保证只要只有一个单例被new
出来。
看起来是没问题的,因为我们想当然的以为,一个线程new
出来的Singleton
,赋值给instance
,然后另一个线程获取到的instance
就一定不是空。实际上呢?
CPU
结构
让我们来看Youtube
上的一张图:
在CPU
内部结构中,thread-1
和thread-2
运行在不同的核心上,每个核心有一个local cache
,两个线程执行时,会将变量从shared cache
读取到local cache
。
所以thread-1
把flag
内容改变了,但是thread-2
获取的flag
还是从local cache
中获取的,所以还是true
。
直到,thread-1
的flag
更新到shared cache
,然后再更新到thread-2
的local cache
,thread-2
才知道flag
变了。
所以我们的单例也一样,线程A
新建了单例,然后其他线程再获取的时候,不一定是线程A
所创建的单例对象。
拯救世界
volatile
来拯救世界了。
private static volatile Singleton instance;
volatile
做了两件事,强制将local cache
写入到shared cache
,同时使其他核心中的local cache
对该数据的缓存无效。
所以,完整的单例应该是这样:
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
真正的单例
上面的讲解只是为了让大家了解Java
中volatile
的作用,实际的单例并不这样实现,而是使用私有静态内部类实现懒汉模式,当访问getInstance
方法时,才加载Holder
类,实例化单例。
public class Singleton {
private static class Holder {
private static Singleton instance = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return Holder.instance;
}
}
呼,长出了一口气,两个晚上了,总算把volatile
自己学会然后讲明白了,这个应该是发生的概率很小很小,我为了让volatile
的验证让大家都看到,使用JDK
自带的线程池,模拟实际的多线程环境,分别执行自己的测试代码,但还是没出现问题。
HTTP
301/302
去火狐开发者文档看看:
301 Moved Permanently
永久重定向,请求的资源已经被移动到了由Location
头部指定的url
上,搜索引擎会根据该响应修正。
HTTP
升级到HTTPS
时应该能用到。
302 Found
临时重定向,请求的资源被暂时的移动到了由Location
头部指定的url
上。浏览器会重定向到这个url
,但是搜索引擎不会对该资源的链接进行更新。
可能会在某个后台服务瘫痪的时候再转给别的后台服务器时用到?
生产者消费者
至于最后的生产者消费者算法问题,我觉得意义不大,毕竟操作系统的课本出自七
位河北工业大学操作系统教师之手。
JDK
中有阻塞队列,用的就是生产者消费者模型。用到的时候再说吧。
总结
每个人都是优秀的人,每个人都值得尊敬。
软件生而自由,不受世俗污染,不受凡尘打扰,我祝愿每一位软件工程师都能生活在自由、快乐之中。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。