Java性能调优实战
刘超
金山软件西山居技术经理
立即订阅
7535 人已学习
课程目录
已完结 48 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 怎样才能做好性能调优?
免费
模块一 · 概述 (2讲)
01 | 如何制定性能调优标准?
02 | 如何制定性能调优策略?
模块二 · Java编程性能调优 (10讲)
03 | 字符串性能优化不容小觑,百M内存轻松存储几十G数据
04 | 慎重使用正则表达式
05 | ArrayList还是LinkedList?使用不当性能差千倍
加餐 | 推荐几款常用的性能测试工具
06 | Stream如何提高遍历集合效率?
07 | 深入浅出HashMap的设计与优化
08 | 网络通信优化之I/O模型:如何解决高并发下I/O瓶颈?
09 | 网络通信优化之序列化:避免使用Java序列化
10 | 网络通信优化之通信协议:如何优化RPC网络通信?
11 | 答疑课堂:深入了解NIO的优化实现原理
模块三 · 多线程性能调优 (10讲)
12 | 多线程之锁优化(上):深入了解Synchronized同步锁的优化方法
13 | 多线程之锁优化(中):深入了解Lock同步锁的优化方法
14 | 多线程之锁优化(下):使用乐观锁优化并行操作
15 | 多线程调优(上):哪些操作导致了上下文切换?
16 | 多线程调优(下):如何优化多线程上下文切换?
17 | 并发容器的使用:识别不同场景下最优容器
18 | 如何设置线程池大小?
19 | 如何用协程来优化多线程业务?
20 | 答疑课堂:模块三热点问题解答
加餐 | 什么是数据的强、弱一致性?
模块四 · JVM性能监测及调优 (6讲)
21 | 磨刀不误砍柴工:欲知JVM调优先了解JVM内存模型
22 | 深入JVM即时编译器JIT,优化Java编译
23 | 如何优化垃圾回收机制?
24 | 如何优化JVM内存分配?
25 | 内存持续上升,我该如何排查问题?
26 | 答疑课堂:模块四热点问题解答
模块五 · 设计模式调优 (6讲)
27 | 单例模式:如何创建单一对象优化系统性能?
28 | 原型模式与享元模式:提升系统性能的利器
29 | 如何使用设计模式优化并发编程?
30 | 生产者消费者模式:电商库存设计优化
31 | 装饰器模式:如何优化电商系统中复杂的商品价格策略?
32 | 答疑课堂:模块五思考题集锦
模块六 · 数据库性能调优 (8讲)
33 | MySQL调优之SQL语句:如何写出高性能SQL语句?
34 | MySQL调优之事务:高并发场景下的数据库事务调优
35 | MySQL调优之索引:索引的失效与优化
36 | 记一次线上SQL死锁事故:如何避免死锁?
37 | 什么时候需要分表分库?
38 | 电商系统表设计优化案例分析
39 | 数据库参数设置优化,失之毫厘差之千里
40 | 答疑课堂:MySQL中InnoDB的知识点串讲
模块七 · 实战演练场 (4讲)
41 | 如何设计更优的分布式锁?
42 | 电商系统的分布式事务调优
43 | 如何使用缓存优化系统性能?
44 | 记一次双十一抢购性能瓶颈调优
结束语 (1讲)
结束语 | 栉风沐雨,砥砺前行!
Java性能调优实战
登录|注册

09 | 网络通信优化之序列化:避免使用Java序列化

刘超 2019-06-08
你好,我是刘超。
当前大部分后端服务都是基于微服务架构实现的。服务按照业务划分被拆分,实现了服务的解耦,但同时也带来了新的问题,不同业务之间通信需要通过接口实现调用。两个服务之间要共享一个数据对象,就需要从对象转换成二进制流,通过网络传输,传送到对方服务,再转换回对象,供服务方法调用。这个编码和解码过程我们称之为序列化与反序列化。
在大量并发请求的情况下,如果序列化的速度慢,会导致请求响应时间增加;而序列化后的传输数据体积大,会导致网络吞吐量下降。所以一个优秀的序列化框架可以提高系统的整体性能。
我们知道,Java 提供了 RMI 框架可以实现服务与服务之间的接口暴露和调用,RMI 中对数据对象的序列化采用的是 Java 序列化。而目前主流的微服务框架却几乎没有用到 Java 序列化,SpringCloud 用的是 Json 序列化,Dubbo 虽然兼容了 Java 序列化,但默认使用的是 Hessian 序列化。这是为什么呢?
今天我们就来深入了解下 Java 序列化,再对比近两年比较火的 Protobuf 序列化,看看 Protobuf 是如何实现最优序列化的。

Java 序列化

在说缺陷之前,你先得知道什么是 Java 序列化以及它的实现原理。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java性能调优实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(22)

  • 陆离
    序列化会通过反射调用无参构造器返回一个新对象,破坏单例模式。
    解决方法是添加readResolve()方法,自定义返回对象策略。

    作者回复: 回答正确

    2019-06-08
    1
    38
  • kevin
    老师请教下,为什么spring cloud不使用protobuf, thrift等性能更高、支持跨平台的序列化工具,而且使用json?

    作者回复: springcloud是spring生态中的一部分,就目前spring生态很少引入非生态框架。但是我们可以自己实现springcloud兼容protobuf序列化。

    2019-06-09
    4
  • 疯狂咸鱼
    它会在反序列化过程中来验证序列化对象是否加载了反序列化的类,如果是具有相同类名的不同版本号的类,在反序列化中是无法获取对象的。老师,这句话能举个例子么,没太明白

    作者回复: 在Class类文件中默认会有一个serialNo作为序列化对象的版本号,无论在序列化方还是在反序列化方的class类文件中都存在一个默认序列号,在序列化时,会将该版本号加载进去,在反序列化时,会校验该版本号。

    2019-09-14
    3
  • waniz
    老师您好,Java序列化将数据转化为二进制字节流,json序列化将数据转化为json字符串。但是在物理层数据都是以电信号或模拟信号传输。那么从应用层到物理层数据的编码状态究竟是怎么变化的?出发点不同,最后都是二进制传输…忘解惑

    作者回复: Java序列化是将Java对象转化为二进制流,而Json序列化是将Json字符串转为二进制的过程,只是包装的数据格式不一样。

    2019-07-05
    3
  • -W.LI-
    文中说Java序列化,不会序列化静态变量,这个单例的静态变量会被怎么处理啊?

    作者回复: 是的,Java序列化会调用构造函数,构造出一个新对象

    2019-06-08
    3
  • 密码123456
    看到提问,才发现这竟然不是单例。回想内容是因为。可以把类路径上几乎所有实现了 Serializable 接口的对象都实例化。还真不知道怎么写?内部私有类实现,这种可以吗?

    作者回复: 线上代码发生错位了,已修正。

    导致这个问题的原因是序列化中的readObject会通过反射,调用没有参数的构造方法创建一个新的对象。

    所以我们可以在被序列化类中重写readResolve方法。

    private Object readResolve(){
            return singleInstance;
    }

    2019-06-08
    3
  • td901105
    老师我想问一下如果使用非Java的序列化方式的话需要实现Serializable接口吗?
    2019-12-05
  • yunfeng
    2019.10.14 打卡:选择序列化四个原则:编解码效率、所占空间、安全、是否支持多语言
    2019-10-14
  • 疯狂咸鱼
    那么java的NIO用到了java的序列化和反序列化么?有一样的问题么

    作者回复: NIO是一种通信模型,并没有包含序列化的内容,可以自己选择使用哪一种序列化

    2019-09-14
  • 疯狂咸鱼
    老师,所有在网络中传输信息都是要序列化么

    作者回复: 是的,不序列化与反序列化,则无法在内存中获取具体的信息用于业务逻辑中。

    2019-09-14
  • godtrue
    课后思考及问题
    1:老师能深入细致的讲讲JAVA怎么实现序列化的嘛?比如:一个对象怎么一步步神奇的变成一个字节数组的?对象中的属性、属性值、方法、以及此对象的信息怎么变成一个字节数组的?
    2:我们知道对象是通过在 ObjectInputStream 上调用 readObject() 方法进行反序列化的,这个方法其实是一个神奇的构造器,它可以将类路径上几乎所有实现了 Serializable 接口的对象都实例化。
    这个神奇的构造器的实现原理是啥?一个字节数组他怎么将其转换为一个对象的?很好奇,他知道字节数组多少位表示啥意思?然后一段一段的取,一段的翻译嘛?老师给讲讲呗?
    老师深入讲一下原理实现细节,API式的讲解不过瘾,和老师要深入理解的风格也不符呀😄

    作者回复: 序列化是将一个对象通过某种数据结构包装好对象中的具体属性和值,转换为二进制进行网络传输的一个过程。例如一个int类型的属性,数组是1000,转换为二进制则是4个字节的byte数组了。

    后面我会使用一个具体的例子来优化讲解这一讲。

    2019-09-07
  • Jerry
    老师,我试着写了一下这个问题的代码,但是发现Singleton 序列化和反序列化后会产生两个instance, 这个问题怎么解?以下是我的代码,
    '''
    ...
    public static void serializeMe() {
            try {
                ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("SingletonData.txt"));
                oos.writeObject(Singleton.getInstance());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public static Object deSerializeMe() {
            Object obj = null;
            try {
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream("SingletonData.txt"));
                obj = ois.readObject();
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
            return obj;
        }

        private static class Singleton implements Serializable {
            int i;
            private static Singleton instance = null;
            private Singleton() {
                System.out.println("Executing constructor");
                i = 1;
            }

            // key change here !!!
            private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
                System.out.println("readObject before [i=" + i + "]");
                ois.defaultReadObject();
                instance = this; // After de-serialization, two objects of 'Singleton' class are created.
                System.out.println("readObject after [i=" + i + "]");
            }

            // thread unsafe here, don't care
            public static Singleton getInstance() {
                if (instance == null) {
                    instance = new Singleton();
                }
                System.out.println("An instance is returned");
                return instance;
            }

            // readResolve() is usually called after readObject()
            public Object readResolve() {
                System.out.println("Executing readResolve");
                return instance;
            }

            @Override
            public String toString() {
                return "Singleton [i=" + i + "]";
            }
        }
    '''
    2019-07-25
  • hession是通过什么做序列化的?

    作者回复: hessian是用的hessian2序列化。

    2019-07-19
  • 强哥
    首先为什么单例要实现Serializable接口呢?如果本身就不合理,那直接删掉Serializable即可,没必要为了本身的不合理,添加多余的方法,除非有特殊场景,否则这么这样的代码指定会被ugly
    2019-06-19
  • 17702158422
    可以定义一个静态属性 boolean flag = false, 在构造函数里 判断 flag是否为ture, 如果为true则抛出异常,否则将flag赋值为 true ,则可以在运行期防止反序列化时通过反射破坏单例模式
    2019-06-19
  • 草帽路飞
    老师,您好。Java 序列化的安全性中,序列化的时候执行按段循环对象链的代码为什么会导致 hashcode 成倍增长呀?
    2019-06-19
  • undifined
    老师 我们有一个需求,需要将一些更新前的数据保存起来用于回滚,保存的对象有一个 value 属性是 Object 类型的,赋值 BigDecimal 后使用 FastJson 序列化保存到数据库,回滚的时候再反序列化变成了Integer,考虑将 FastJson 改成 JDK 的序列化,但是又担心会造成性能问题,请问老师有什么建议吗

    作者回复: 请问改成JDK序列化的目的是什么?

    2019-06-11
  • Demon.Lee
    图一中,输入流ObjectInputStream应该是反序列吧,输出流ObjectOutputStream应该是序列化吧,老师我理解错了?

    作者回复: 是的,你理解没有错。ObjectInputStream对应readObject,ObjectOutputStream对应writeObject。

    2019-06-11
  • Liam
    在java序列号安全性那里有个疑问,为什么反序列化会导致hashCode方法的频繁调用呢,反序列化时调用hashCode的作用是

    作者回复: 这里不是序列化调用hashcode方法,而是序列化时,运行这段代码。

    2019-06-09
  • 晓杰
    不是单例,因为在反序列化的时候,会调用ObjectInputStream的readObject方法,该方法可以对实现序列化接口的类进行实例化,所以会破坏单例模式。
    可以通过重写readResolve,返回单例对象的方式来避免这个问题

    作者回复: 正确

    2019-06-08
收起评论
22
返回
顶部