詳解Java如何利用數(shù)字描述更多的信息
一 . 前言
這一篇來趣味性的探討一下 , 如何通過更少的空間描述更多的信息
在數(shù)據(jù)庫里面 ,通常我們會用數(shù)字的遞進(jìn)來描述狀態(tài)等信息 , 但是如果想進(jìn)行更復(fù)雜的操作 , 就有必要對二進(jìn)制有一定理解了.
二 . 單數(shù)中描述信息
單數(shù)中保存多個信息的意思是 : 我們能把多少信息存儲到一串?dāng)?shù)字里面. 這里直接來通過一些案例來說明用法
用單個數(shù)字來表示狀態(tài)
這也是業(yè)務(wù)中最常見的一種使用方式 , 通過數(shù)字 1,2,3 等來描述一個狀態(tài) , 這種方式有一定的可讀性 , 也有足夠的擴(kuò)展性
如果從二進(jìn)制的角度說 , 這是一種進(jìn)位體現(xiàn)狀態(tài)的方式.
用單個數(shù)字來描述多個狀態(tài) : 包含多種狀態(tài)
單數(shù)描述多個信息這一塊首先能想到的就是 Linux 的權(quán)限表示法 , 在Linux 中有四種權(quán)限 , 分別如下 :
這種表示法的方式很簡單, 從表象上來說就是兩數(shù)相加 , 把初始狀態(tài)設(shè)為 1 / 2 / 4 , 更復(fù)雜的狀態(tài)則是初始狀態(tài)的組合.
這種模式從二進(jìn)制的角度看的話能更明顯 , 每一位都標(biāo)識一種狀態(tài).在更復(fù)雜的場景中, 還可以通過質(zhì)數(shù)的數(shù)學(xué)特性 , 來做更多的擴(kuò)展
用單個數(shù)字來描述不同維度的信息 : 包含狀態(tài)和數(shù)量
這種體現(xiàn)最有代表的就是線程池的表現(xiàn)方式. 在線程池對象ThreadPoolExecutor 中 , 有個屬性可秀了 , 它叫 ctl.
// ctl 是一個整形原子類 , 它即表示了狀態(tài) , 有記錄了梳理 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); // : 此變量 記錄了 “線程池中的任務(wù)數(shù)量”和“線程池的狀態(tài)”兩個信息 // : 高3位表示"線程池狀態(tài)",低29位表示"線程池中的任務(wù)數(shù)量" // - RUNNING : 111 : 該線程池能接收新任務(wù) ,且能對新任務(wù)進(jìn)行處理 // - SHUTDOWN : 000 : 不能接收新任務(wù) ,但是可以對任務(wù)進(jìn)行處理 // - STOP : 001 : 不添加新任務(wù) , 不對任務(wù)進(jìn)行處理 , 會中斷正在執(zhí)行的任務(wù) // - TIDYING : 010 : 當(dāng)所有的任務(wù)已終止,ctl記錄的"任務(wù)數(shù)量"為0,線程池會變?yōu)門IDYING狀態(tài) // - 當(dāng)所有的任務(wù)已終止,ctl記錄的"任務(wù)數(shù)量"為0,線程池會變?yōu)門IDYING狀態(tài) // - TERMINATED : 011 : 線程池徹底終止的狀態(tài) // 對數(shù)量的統(tǒng)計(jì)很簡單 , 因?yàn)槭?低 29 位用來描述梳理 , 所以做正常的加減即可實(shí)現(xiàn) private boolean compareAndIncrementWorkerCount(int expect) { return ctl.compareAndSet(expect, expect + 1); } private boolean compareAndDecrementWorkerCount(int expect) { return ctl.compareAndSet(expect, expect - 1); } // 對狀態(tài)的修改則是通過位運(yùn)算來做的 > S1 : 預(yù)先準(zhǔn)備多種狀態(tài) private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS; > S2 : 判斷是否是運(yùn)行狀態(tài)或停止?fàn)顟B(tài) private static final int COUNT_BITS = Integer.SIZE - 3; private static final int CAPACITY = (1 << COUNT_BITS) - 1; // ~CAPACITY將反轉(zhuǎn)CAPACITY的值,也就是CAPACITY的高3位全部為1,低29位全部為0 // & 操作則可以得到高三位的值 private static int runStateOf(int c) { return c & ~CAPACITY; } final boolean isRunningOrShutdown(boolean shutdownOK) { int rs = runStateOf(ctl.get()); return rs == RUNNING || (rs == SHUTDOWN && shutdownOK); }
這樣一個數(shù)字則將數(shù)據(jù)進(jìn)行了深度擴(kuò)展 , 了解一定的二進(jìn)制思想就足夠了解這些邏輯的變化
三. 宏觀思路
雪花算法對數(shù)字的整合
下面說的幾種方式會跳出二進(jìn)制 , 從業(yè)務(wù)的角度去看數(shù)字的玩法 , 先來看一段很常見的雪花算法
3 << 60 | timestamp - 1504000000000L << 20 | workerId << 10 | random.nextInt(128);
首位 : 可以自定義首位
時(shí)間戳 : 可以根據(jù)自己的業(yè)務(wù)情況定義毫秒級 (這里我隨便給了個時(shí)間)
工作機(jī)器id:也被叫做workId,這個可以靈活配置,機(jī)房或者機(jī)器號組合都可以
隨機(jī)序列號 : 自增值支持同一毫秒內(nèi)同一個節(jié)點(diǎn)可以生成隨機(jī)多少個ID
類似的方式還可以有很多 , 一個數(shù)有很長的位數(shù) , 我們可以通過這些位數(shù)來實(shí)現(xiàn)不同的業(yè)務(wù)邏輯 , 以表達(dá)不同的涵義.
偏移量對進(jìn)度的處理
說到偏移量 , 最簡單的方向就是 for 循環(huán)時(shí)對 size 進(jìn)行判斷 ,當(dāng)達(dá)到 size 后直接結(jié)束.
而稍微復(fù)雜點(diǎn)的就是 IO 流種對長度進(jìn)行讀取, 分批去讀取數(shù)據(jù).
更深度一點(diǎn)的就是即進(jìn)行長度的擴(kuò)展 , 又包含其他的信息 , 這一篇就來看一下 ObjectStream 中如何使用偏移量的.
ObjectStream 是一個對象流 , 通過 JDK 序列化對對象進(jìn)行轉(zhuǎn)換和解析.
在下面這個場景中 , 有一個對象叫 passHandle , ObjectStream 會通過該值作為下標(biāo)獲取存在對象列表中的對象 , 同時(shí)通過該對象判斷整體的進(jìn)度已經(jīng)狀態(tài)
// S1 : 初始化 private static final int NULL_HANDLE = -1; private int passHandle = NULL_HANDLE; // S2 : 寫入 passHandler (PS : 此處是在 ObjectOutputStream 中) bout.writeInt(baseWireHandle + passHandle); // S3 : 解析 passHandler passHandle = bin.readInt() - baseWireHandle; if (passHandle < 0 || passHandle >= handles.size()) { throw new StreamCorruptedException... } // S4 : 通過 Handler 取位數(shù) Object lookupObject(int handle) { return (handle != NULL_HANDLE && status[handle] != STATUS_EXCEPTION) ? entries[handle] : null; }
除了作為偏移量來確定進(jìn)度 , 還可以通過 passHandler 來標(biāo)識狀態(tài)
通常用偏移量來標(biāo)識狀態(tài)是需要和其他對象相配合的 , 例如集合 :
在下面這個案例里面 , passHandler 是作為 status 的下標(biāo)存在的 , 而每個下標(biāo)中都會存儲一個狀態(tài), 則就對整個序列化中的狀態(tài)進(jìn)行了統(tǒng)計(jì) :
private static final byte STATUS_OK = 1; private static final byte STATUS_UNKNOWN = 2; private static final byte STATUS_EXCEPTION = 3;
在這個案例里面 , 游標(biāo)本身只代表了定位 , 但是它可以配合多個其他的對象 , 來擴(kuò)展其含義. 同時(shí)游標(biāo)可以通過設(shè)置負(fù)數(shù)形式 , 來擴(kuò)展其狀態(tài)含義. 當(dāng)其等于 -1 時(shí) , 則標(biāo)識不存在該對象 , 是另外一種層面的擴(kuò)展
總結(jié)
對數(shù)據(jù)的信息處理其實(shí)還有很多種方式 , 總結(jié)出來主要包括以下幾種 :
- 簡單的通過其遞增的變化 , 來對應(yīng)不同的狀態(tài)
- 通過數(shù)字的疊加 , 來記錄多種狀態(tài)的疊加
- 通過二進(jìn)制內(nèi)不同的位數(shù) , 來記錄多種層面的數(shù)據(jù)
- 通過 long 等長位數(shù) , 來為不同的位數(shù)匹配不同的含義
- 通過作為一個游標(biāo) ,配合其他的對象做更深度的擴(kuò)展
到此這篇關(guān)于詳解Java如何利用數(shù)字描述更多的信息的文章就介紹到這了,更多相關(guān)Java描述信息內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis映射文件中parameterType與resultType的用法詳解
MyBatis中的ParameterType指的是SQL語句中的參數(shù)類型,即傳入SQL語句中的參數(shù)的類型,下面這篇文章主要給大家介紹了關(guān)于MyBatis映射文件中parameterType與resultType用法的相關(guān)資料,需要的朋友可以參考下2023-04-04淺談Spring Cloud zuul http請求轉(zhuǎn)發(fā)原理
這篇文章主要介紹了淺談Spring Cloud zuul http請求轉(zhuǎn)發(fā)原理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08