12

引言

最近好久没有遇到技术瓶颈了,思考得自然少了,每天都是重复性的工作。

阿里开始招实习,同学问我要不要去申请阿里的实习,我说不去,个人对阿里的印象不好。

记得去年阿里给我发了邮件,我很认真地回复,然后他不理我了。(最起码的尊重都没有,就算我菜你起码回复我一下啊?)

这种不尊重人的公司感觉去了也不快乐,当程序员最重要的就是快乐,不快乐写什么代码?

clipboard.png

电话面

同学很友好地分享了他的阿里电话面经验。

问的都是看功底的问题,和开发经验无关(估计写上个几年代码不写框架应该也不知道这个)。

Java中的HashMaptransientvolatileHTTP301/302、生产者消费者算法。

HashMap都问烂了,问的是HashMap的底层原理,我知道你们自己写过JDK,请不要再问我HashMap里的put操作是怎么实现的了!

问源码的真的很讨厌,有什么意义吗?看过的就能答上,没看过的就答不上。

基础学习

transient

这并不是第一次听到transient这个词了,之前也用过,当我们使用YunzhiService进行综合查询时,我们会在实体中构造不映射到数据表的属性用于查询。

对于这些不映射为数据表字段的属性,我们使用@Transient注解。

Java中被transient修饰又是什么意思呢?

clipboard.png

为什么要有transientStackOverflow的解释通俗易懂。

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应该用到了这个关键字。

clipboard.png

厉害厉害,fastjson开发团队基本功扎实。

volatile

这个关键字也不知道怎么能给大家通俗的讲出来,还是从实际的小例子出发吧?

大家回忆一下我们之前的单例模式,单例模式很常用,这个是必须要会的。

这是有问题的懒汉模式,多线程的时候就不能保持单例了。

public class Singleton {

    private static Singleton instance;

    private Singleton() {

    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

修正之前的问题

clipboard.png

纠正一下之前博客中的一个问题,之前这样写虽然也能实现,但是效率极低,因为每次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上的一张图:

clipboard.png

CPU内部结构中,thread-1thread-2运行在不同的核心上,每个核心有一个local cache,两个线程执行时,会将变量从shared cache读取到local cache

所以thread-1flag内容改变了,但是thread-2获取的flag还是从local cache中获取的,所以还是true

直到,thread-1flag更新到shared cache,然后再更新到thread-2local cachethread-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;
    }
}

真正的单例

上面的讲解只是为了让大家了解Javavolatile的作用,实际的单例并不这样实现,而是使用私有静态内部类实现懒汉模式,当访问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,但是搜索引擎不会对该资源的链接进行更新。

可能会在某个后台服务瘫痪的时候再转给别的后台服务器时用到?

生产者消费者

至于最后的生产者消费者算法问题,我觉得意义不大,毕竟操作系统的课本出自位河北工业大学操作系统教师之手。

clipboard.png

JDK中有阻塞队列,用的就是生产者消费者模型。用到的时候再说吧。

总结

每个人都是优秀的人,每个人都值得尊敬。

软件生而自由,不受世俗污染,不受凡尘打扰,我祝愿每一位软件工程师都能生活在自由、快乐之中。


张喜硕
2.1k 声望423 粉丝

浅梦辄止,书墨未浓。