转载

重拾 Java 基础

引言

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

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

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

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

重拾 Java 基础

电话面

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

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

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

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

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

基础学习

transient

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

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

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

重拾 Java 基础

为什么要有 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 应该用到了这个关键字。

重拾 Java 基础

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

volatile

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

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

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

public class Singleton {

    private static Singleton instance;

    private Singleton() {

    }

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

修正之前的问题

重拾 Java 基础

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

重拾 Java 基础

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 ,但是搜索引擎不会对该资源的链接进行更新。

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

生产者消费者

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

重拾 Java 基础

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

总结

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

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

原文  https://segmentfault.com/a/1190000018665133
正文到此结束
Loading...