1. 程式人生 > >Java 序列化界新貴 kryo 和熟悉的“老大哥”,就是 PowerJob 的序列化方案

Java 序列化界新貴 kryo 和熟悉的“老大哥”,就是 PowerJob 的序列化方案

> 本文適合有 Java 基礎知識的人群 ![](https://img2020.cnblogs.com/blog/759200/202009/759200-20200909174107138-417844958.png) 作者:HelloGitHub-**Salieri** HelloGitHub 推出的[《講解開源專案》](https://github.com/HelloGitHub-Team/Article)系列。 > 專案地址: > > https://github.com/KFCFans/PowerJob 序列化與反序列化一直是分散式程式設計中無法繞開的話題。PowerJob 作為一個完全意義上的分散式系統,自然少不了節點通訊時不可避免的序列化問題。由於 PowerJob 定位是中介軟體,出於對效能的追求,在序列化上自然也是花費了不少時間去雕琢。以下是整個過程中的一些經驗與分享,希望對大家有所幫助。 ## 一、序列化界新貴:kryo kryo 作為目前最快的序列化框架,自然受到了我的青睞。在 PowerJob 中,kryo 是內建預設的序列化框架。下面為大家介紹 kryo 的用法。 ### 1.1 基礎用法 對於序列化框架來說,API 其實都差不多,畢竟入參和出參都定義好了(一個是需要序列化的物件,一個是序列化後的結果,比如位元組陣列)。下面簡單介紹下 kryo 的基礎用法,由於序列化和反序列化類似,以下使用序列化來作為演示。 ```java Kryo kryo = new Kryo(); try (Output opt = new Output(1024, -1)) { kryo.writeClassAndObject(opt, obj); opt.flush(); return opt.getBuffer(); } ``` 程式碼很簡單,首先需要建立兩個物件:Kryo 和 Output。其中,Kryo 是序列化主角,負責完成實際的序列化/反序列化工作。而 Output 則是 kryo 框架封裝的流物件,用於儲存序列化後的二進位制資料。當兩個物件都準備完畢後,呼叫 `kryo.writeClassAndObject(opt, obj)` 方法即可完成物件的序列化,最後呼叫 Output 流物件的 `getBuffer()` 方法獲取序列化結果,也就是二進位制陣列。 ### 1.2 執行緒不安全 相信大家都用過 fastjson,初次接觸 fastjson 肯定會被它簡單的 API 所吸引,常用的序列化/反序列化統統一行程式碼搞定,比如 `JSON.toJSONString()`。通常來說,這種通過靜態方法暴露的 API,其背後的設計與實現都是**執行緒安全**的,也就是在多執行緒環境中,你可以安心的使用 fastjson 的靜態方法進行序列化和反序列化,那麼 kryo 可以嗎? 從上述程式碼不難看出,不可以~否則,人家為什麼要多次一舉讓你建立物件提高使用成本呢? 王進喜同志說過,沒有條件就創造條件。既然 kryo 官方不提供靜態方法讓我們簡單使用,那就自己封裝一個吧~ ![](https://img2020.cnblogs.com/blog/759200/202009/759200-20200909174115281-1808323918.png) 拋開效能因素,封裝一個工具類非常簡單,畢竟我們的目標是解決 kryo 的併發安全問題,而當沒有任何共享資源時,是不存在任何併發安全問題的。那麼我們只需要在剛剛的例項程式碼上,套上一個靜態方法,就完成了最簡單的kryo 工具類封裝,程式碼示例如下: ```java public static byte[] serialize(Object obj) { Kryo kryo = new Kryo(); try (Output opt = new Output(1024, -1)) { kryo.writeClassAndObject(opt, obj); opt.flush(); return opt.getBuffer(); } } ``` 安全問題是解決了,但...事情往往不會那麼簡單。這種模式下,每一次呼叫都會重複建立 2 個新物件(Kryo 和 Output),這在高併發下會產生一筆不小的開銷。為了獲取效能的提升,自然要考慮到物件的複用問題。物件的複用常用解決方案有兩個,分別是物件池和 ThreadLocal,下面分別進行介紹。 ### 1.3 物件池 在程式設計中,“池”這個名詞相信大家一定不陌生。執行緒池、連線池已經是併發程式設計中不可避免的一部分。“池”重複利用了複用的思想,將建立完後的物件通過某個容器儲存起來反覆使用,從而達到提升效能的作用。Kryo 物件池原理上便是如此。Kryo 框架自帶了物件池的實現,因此使用非常簡單,不外乎**建立池、從池中獲取物件、歸還物件**三步,以下為程式碼例項。 首先,建立 Kryo 物件池,通過重寫 Pool 介面的 create 方法,便可創建出自定義配置的物件池。 ```java private static fi