Kryo 高性能序列化和反序列化

news/2024/7/17 13:50:44

一、pom.xml

<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>kryo</artifactId>
    <version>4.0.0</version>
</dependency>

二、封装工具类

package com.cxs.web.system.kryo;

import com.cxs.common.util.ArrayUtil;
import com.cxs.common.util.Collections;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.pool.KryoCallback;
import com.esotericsoftware.kryo.pool.KryoFactory;
import com.esotericsoftware.kryo.pool.KryoPool;
import org.objenesis.strategy.StdInstantiatorStrategy;
import org.springframework.util.StopWatch;

import java.io.*;
import java.util.*;

/**
 * KryoUtils序列化和反序列化操作
 官方文档:
 中文:https://blog.csdn.net/fanjunjaden/article/details/72823866
 英文:https://github.com/EsotericSoftware/kryo
 */
public class KryoUtils  {
    /* Kryo有三组读写对象的方法
     * 1.如果不知道对象的具体类,且对象可以为null: kryo.writeClassAndObject(output, object); Object object = kryo.readClassAndObject(input);
     * 2.如果类已知且对象可以为null: kryo.writeObjectOrNull(output, someObject); SomeClass someObject = kryo.readObjectOrNull(input, SomeClass.class);
     * 3.如果类已知且对象不能为null:  kryo.writeObject(output, someObject); SomeClass someObject = kryo.readObject(input, SomeClass.class);
     */
    /**
     * (池化Kryo实例)使用ThreadLocal
     */
    private static final ThreadLocal<Kryo> KRYOS = new ThreadLocal<Kryo>() {
        @Override
        protected Kryo initialValue() {
            Kryo kryo = new Kryo();
            /**
             * 不要轻易改变这里的配置,更改之后,序列化的格式就会发生变化,
             * 上线的同时就必须清除 Redis 里的所有缓存,
             * 否则那些缓存再回来反序列化的时候,就会报错
             */
            //支持对象循环引用(否则会栈溢出)
            kryo.setReferences(true); //默认值就是 true,添加此行的目的是为了提醒维护者,不要改变这个配置
            //不强制要求注册类(注册行为无法保证多个 JVM 内同一个类的注册编号相同;而且业务系统中大量的 Class 也难以一一注册)
            kryo.setRegistrationRequired(false); //默认值就是 false,添加此行的目的是为了提醒维护者,不要改变这个配置
            //Fix the NPE bug when deserializing Collections.
            ((Kryo.DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy()).setFallbackInstantiatorStrategy(new StdInstantiatorStrategy());
            return kryo;
        }
    };
    /**
     * (池化Kryo实例)使用KryoPool
     */
    /*private static KryoFactory factory1 = new KryoFactory() {
        @Override
        public Kryo create () {
            return new Kryo();
        }
    };
    private static KryoFactory  factory2 = () -> { return new Kryo(); };
    private static KryoFactory  factory3 = () -> new Kryo();*/
    private static KryoFactory  factory = Kryo::new;
    private static KryoPool pool = new KryoPool.Builder(factory).softReferences().build();



    /**
     * 使用ThreadLocal创建Kryo
     * 把java对象序列化成byte[];
     * @param obj java对象
     * @return
     */
    public static <T>  byte[] serializeObject(T obj) {
        ByteArrayOutputStream os=null;
        Output output=null;
        if(null != obj){
            Kryo kryo = KRYOS.get();
            try {
                os = new ByteArrayOutputStream();
                output = new Output(os);
                kryo.writeObject(output, obj);
                close(output);
                return os.toByteArray();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                close(os);

            }
        }
        return null;
    }

    /**
     * 使用ThreadLocal创建Kryo
     * 把byte[]反序列化成指定的java对象
     * @param bytes
     * @param t 指定的java对象
     * @param <T>
     * @return 指定的java对象
     */
    public static <T> T unSerializeObject(byte[] bytes,Class<T> t) {
        ByteArrayInputStream is=null;
        Input input=null;
        if(null != bytes && bytes.length>0 && null!=t){
            try {
                Kryo kryo = KRYOS.get();
                is = new ByteArrayInputStream(bytes);
                input = new Input(is);
                return kryo.readObject(input,t);
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                close(is);
                close(input);
            }
        }
        return null;
    }


    /**
     * 使用ThreadLocal创建Kryo
     * 把List序列化成byte[];
     * @param list java对象
     * @return
     */
    public static <T>  byte[]  serializeList(List<T> list ) {
        ByteArrayOutputStream os=null;
        Output output=null;
        byte[] bytes = null;
        if(null != list && list.size()>0){
            Kryo kryo = KRYOS.get();
            try {
                os = new ByteArrayOutputStream();
                output = new Output(os);
                kryo.writeObject(output,list);
                close(output);
                bytes = os.toByteArray();
                return bytes;
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                close(os);
            }
        }
        return null;
    }

    /**
     * 使用ThreadLocal创建Kryo
     * 把byte[]反序列化成指定的List<T>
     * @param bytes byte数组
     * @param <T>
     * @return 指定java对象的List
     */
    public static <T> List<T> unSerializeList(byte[] bytes) {
        ByteArrayInputStream is=null;
        Input input=null;
        if(null !=bytes && bytes.length>0){
            try {
                Kryo kryo = KRYOS.get();
                is = new ByteArrayInputStream(bytes);
                input = new Input(is);
                List<T> list = kryo.readObject(input,ArrayList.class);
                return list;
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                close(is);
                close(input);
            }
        }
        return null;
    }




    /**
     * 使用ThreadLocal创建Kryo
     * 把java对象转序列化存储在文件中;
     * @param obj java对象
     * @return
     */
    public static <T>  boolean serializeFile(T obj,String path) {
        if(null != obj){
            Output output=null;
            try {
                Kryo kryo = KRYOS.get();
                output = new Output(new FileOutputStream(path));
                kryo.writeObject(output, obj);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                close(output);
            }
        }
        return false;
    }

    /**
     * 使用ThreadLocal创建Kryo
     * 把序列化的文件反序列化成指定的java对象
     * @param path 文件路径
     * @param t 指定的java对象
     * @param <T>
     * @return 指定的java对象
     */
    public static <T> T unSerializeFile(String path,Class<T> t) {
        if(null != path && null !=t ){
            Input input=null;
            try {
                Kryo kryo = KRYOS.get();
                input = new Input(new FileInputStream(path));
                return kryo.readObject(input,t);
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                close(input);
            }
        }
        return null;
    }

    /**
     * 使用KryoPool SoftReferences创建Kryo
     * 把java对象序列化成byte[] ;
     * @param obj java对象
     * @return
     */
    public static <T>  byte[] serializePoolSoftReferences (T obj) {
        if(null!=obj){
            Kryo kryo =pool.borrow();
            ByteArrayOutputStream os=null;
            Output output=null;
            try {
                os = new ByteArrayOutputStream();
                output = new Output(os);
                kryo.writeObject(output, obj);
                close(output);
                byte [] bytes = os.toByteArray();
                return bytes;
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                pool.release(kryo);
                close(os);
            }
        }
        return null;
    }
    /**
     * 使用KryoPool SoftReferences创建Kryo
     * 把byte[]反序列化成指定的java对象
     * @param bytes
     * @return
     */
    public static <T> T unSerializePoolSoftReferences(byte[] bytes,Class<T> t) {
        if(null !=bytes && bytes.length>0 && null!=t){
            Kryo kryo =pool.borrow();
            ByteArrayInputStream is=null;
            Output output=null;
            try {
                is = new ByteArrayInputStream(bytes);
                Input input= new Input(is);
                return kryo.readObject(input, t);
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                pool.release(kryo);
                close(is);
                close(output);
            }
        }
        return null;
    }


    /**
     * 使用KryoPool SoftReferences创建Kryo
     * 把java对象序列化成byte[] ;
     * @param obj java对象
     * @return
     */
    public static <T>  byte[] serializePoolCallback (final T obj) {
        if(null != obj){
            try {
                return pool.run(new KryoCallback<byte[]>() {
                    @Override
                    public byte[] execute(Kryo kryo) {
                        ByteArrayOutputStream os = new ByteArrayOutputStream();
                        Output output = new Output(os);
                        kryo.writeObject(output,obj);
                        output.close();
                        try {
                            os.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        return os.toByteArray();
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 使用KryoPool SoftReferences创建Kryo
     * 把byte[]反序列化成指定的java对象
     * @param bytes
     * @return
     */
    public static <T> T unSerializePoolCallback(final byte[] bytes, final Class<T> t) {
        if(null != bytes && bytes.length>0 && null != t){
            try {
                return pool.run(new KryoCallback<T>() {
                    @Override
                    public T execute(Kryo kryo) {
                        ByteArrayInputStream is = new ByteArrayInputStream(bytes);
                        Input input = new Input(is);
                        T result =kryo.readObject(input,t);
                        input.close();
                        try {
                            is.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        return result;
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 关闭io流对象
     *
     * @param closeable
     */
    public static void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    public static void main(String[] args) throws FileNotFoundException {
        Clazz clazz1 = new Clazz("3年级1班", "java", 1);
        Clazz clazz2 = new Clazz("3年级2班", ".net", 2);
        Clazz clazz3 = new Clazz("3年级3班", "vue", 3);

        Student student1 = new Student("张三", 18, new Date(), '1', true, clazz1);
        Student student2 = new Student("李四", 28, new Date(System.currentTimeMillis()-1000*60*60*24), '1', true, clazz1);
        Student student3 = new Student("王五", 38, new Date(System.currentTimeMillis()-1000*60*60*24*2), '2', false, clazz2);
        Student student4 = new Student("赵六", 48, new Date(System.currentTimeMillis()-1000*60*60*24*3), '1', true, clazz3);
        Student student5 = new Student("刘七", 58, new Date(System.currentTimeMillis()-1000*60*60*24*4), '2', false, clazz1);

        List<Student> studentList = Arrays.asList(student1, student2, student3, student4, student5);
        System.out.println("===kryo序列化===");
        StopWatch stopWatch = new StopWatch("kryo序列化/反序列化");
        stopWatch.start("kryo序列化/反序列化");
        for(int i = 0; i < 1000000; i++) {
            unSerializeObject(serializeObject(studentList), ArrayList.class);
        }
        stopWatch.stop();
        System.out.println(stopWatch.getId() + "-totalTimeMillis:" + stopWatch.getTotalTimeMillis());

        System.out.println("===jdk序列化===");
        stopWatch = new StopWatch("jdk序列化/反序列化");
        stopWatch.start("jdk序列化/反序列化");
        for(int i = 0; i < 1000000; i++) {
            Collections.deepCopy(studentList);
        }
        stopWatch.stop();
        System.out.println(stopWatch.getId() + "-totalTimeMillis:" + stopWatch.getTotalTimeMillis());
    }
}

三、与jdk序列化/反序列化的性能测试

1. 循环1万次测试

在这里插入图片描述
测试结果:kryo高于jdk 3倍效率

2. 循环10万次测试

在这里插入图片描述
测试结果:kryo高于jdk 4倍效率

3. 循环100万次测试

在这里插入图片描述

测试结果:kryo高于jdk 5倍效率

四、总结

序列化/反序列化 次数越多,效果越明显!


http://www.niftyadmin.cn/n/3654694.html

相关文章

股票技术指标详解--人气指标(AR)

人气指标(AR) 一、人气指标 股市中买卖双方的气势主要反映在每日股指最高点、最低点及开盘价三者之间的关系上。AR指标是利用一定周期内三者的差异以及比值反映出股市强弱、买卖气势的指标。 二、公式 AR(n)∑&#xff08;当日最高价&#xff0d;当日开盘价&#xff09;∑&…

WINX-1.1.01 Released

修订记录 1.1.01 (2006-10-14)-----------------------------------------*) 示范代码&#xff08;tutorials&#xff09;- Hello, SmartWin! tutorials/winx/step001/hello,smartwin (a)- XSL转换(XSLT) tutorials/winx/step018-xslt (b)- 直方图均衡化(OpenCV样例) tutorials…

如何让 HTML识别 String 里的 ‘\r\n‘ 并成功换行显示

在结果所在的 div 的 css 设置&#xff1a; white-space: pre-line;如&#xff1a; <span style"white-space: pre-line;">文本内容 </span>然后页面就能成功识别 ‘\r\n’ 或 ‘\n’ &#xff0c;并换行显示.

OWC学习笔记-图表选中状态

在使用ChartSpace时没有找到选中图形组件的方法或属性&#xff0c;后来找到一种用XMLData参数可以设置选中&#xff0c;不过选中状态不好看&#xff0c;不知道有什么可以改进的。 实现代码&#xff1a; <object idChartSpace1 classidCLSID:0002E55D-0000-0000-C000-00000…

在console中 使用C Runtime 和 STL 显示 Unicode中文

这篇文章应该是[netsin]的成果&#xff0c;我勤快&#xff0c;记下来。注&#xff1a;wprintf是C的标准库函数&#xff0c;但wcout不是C的标准成员&#xff0c;C中的L”……”是宽字符&#xff0c;却未必是unicode字符&#xff0c;这与编译器实现相关。本文中的代码执行环境是 …

RabbitMq发送和接收消息(自动创建队列、交换机和绑定)

自动创建队列、交换机和绑定 一、pom.xml <dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit</artifactId><version>2.0.5.RELEASE</version> </dependency>二、发送者&#xff08;produc…

OWC资料收集-OWC简介及其属性

Figure 3 Office Web Components (version 10)组件描述PivotTable使用户连接到支持 OLE DB Provider for OLAP Services 8.0 或更高版的 OLAP 数据源上 (也可连接到 Excel 电子数据表单 和 SQL Server 、 Access 关系数据库)。PivotTable 控件允许用户对数据进行透视、分组、筛…

右键文件关联

// 获取桌面文件夹 LPSHELLFOLDER lpDeskFolder NULL; ::SHGetDesktopFolder(&lpDeskFolder); if( lpDeskFolder NULL ) { ASSERT(FALSE); return; } int nPathLen m_strFolder.GetLength(); LPITEMIDLIST ParentPidl NULL; DWORD dwEaten 0; USES_CONVERSION; DWORD …