最近好久没有遇到技术瓶颈了,思考得自然少了,每天都是重复性的工作。
阿里开始招实习,同学问我要不要去申请阿里的实习,我说不去,个人对阿里的印象不好。
记得去年阿里给我发了邮件,我很认真地回复,然后他不理我了。(最起码的尊重都没有,就算我菜你起码回复我一下啊?)
这种不尊重人的公司感觉去了也不快乐,当程序员最重要的就是快乐,不快乐写什么代码?
同学很友好地分享了他的阿里电话面经验。
问的都是看功底的问题,和开发经验无关(估计写上个几年代码不写框架应该也不知道这个)。
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
中有阻塞队列,用的就是生产者消费者模型。用到的时候再说吧。
每个人都是优秀的人,每个人都值得尊敬。
软件生而自由,不受世俗污染,不受凡尘打扰,我祝愿每一位软件工程师都能生活在自由、快乐之中。