詳解Java如何利用數(shù)字描述更多的信息
一 . 前言
這一篇來趣味性的探討一下 , 如何通過更少的空間描述更多的信息
在數(shù)據(jù)庫里面 ,通常我們會用數(shù)字的遞進來描述狀態(tài)等信息 , 但是如果想進行更復(fù)雜的操作 , 就有必要對二進制有一定理解了.
二 . 單數(shù)中描述信息
單數(shù)中保存多個信息的意思是 : 我們能把多少信息存儲到一串?dāng)?shù)字里面. 這里直接來通過一些案例來說明用法
用單個數(shù)字來表示狀態(tài)
這也是業(yè)務(wù)中最常見的一種使用方式 , 通過數(shù)字 1,2,3 等來描述一個狀態(tài) , 這種方式有一定的可讀性 , 也有足夠的擴展性
如果從二進制的角度說 , 這是一種進位體現(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)的組合.
這種模式從二進制的角度看的話能更明顯 , 每一位都標(biāo)識一種狀態(tài).在更復(fù)雜的場景中, 還可以通過質(zhì)數(shù)的數(shù)學(xué)特性 , 來做更多的擴展
用單個數(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ù)進行處理
// - SHUTDOWN : 000 : 不能接收新任務(wù) ,但是可以對任務(wù)進行處理
// - STOP : 001 : 不添加新任務(wù) , 不對任務(wù)進行處理 , 會中斷正在執(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)計很簡單 , 因為是 低 29 位用來描述梳理 , 所以做正常的加減即可實現(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)的修改則是通過位運算來做的
> 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 : 判斷是否是運行狀態(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ù)進行了深度擴展 , 了解一定的二進制思想就足夠了解這些邏輯的變化
三. 宏觀思路
雪花算法對數(shù)字的整合
下面說的幾種方式會跳出二進制 , 從業(yè)務(wù)的角度去看數(shù)字的玩法 , 先來看一段很常見的雪花算法
3 << 60 | timestamp - 1504000000000L << 20 | workerId << 10 | random.nextInt(128);
首位 : 可以自定義首位
時間戳 : 可以根據(jù)自己的業(yè)務(wù)情況定義毫秒級 (這里我隨便給了個時間)
工作機器id:也被叫做workId,這個可以靈活配置,機房或者機器號組合都可以
隨機序列號 : 自增值支持同一毫秒內(nèi)同一個節(jié)點可以生成隨機多少個ID
類似的方式還可以有很多 , 一個數(shù)有很長的位數(shù) , 我們可以通過這些位數(shù)來實現(xiàn)不同的業(yè)務(wù)邏輯 , 以表達不同的涵義.
偏移量對進度的處理
說到偏移量 , 最簡單的方向就是 for 循環(huán)時對 size 進行判斷 ,當(dāng)達到 size 后直接結(jié)束.
而稍微復(fù)雜點的就是 IO 流種對長度進行讀取, 分批去讀取數(shù)據(jù).
更深度一點的就是即進行長度的擴展 , 又包含其他的信息 , 這一篇就來看一下 ObjectStream 中如何使用偏移量的.
ObjectStream 是一個對象流 , 通過 JDK 序列化對對象進行轉(zhuǎn)換和解析.
在下面這個場景中 , 有一個對象叫 passHandle , ObjectStream 會通過該值作為下標(biāo)獲取存在對象列表中的對象 , 同時通過該對象判斷整體的進度已經(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;
}
除了作為偏移量來確定進度 , 還可以通過 passHandler 來標(biāo)識狀態(tài)
通常用偏移量來標(biāo)識狀態(tài)是需要和其他對象相配合的 , 例如集合 :
在下面這個案例里面 , passHandler 是作為 status 的下標(biāo)存在的 , 而每個下標(biāo)中都會存儲一個狀態(tài), 則就對整個序列化中的狀態(tài)進行了統(tǒng)計 :
private static final byte STATUS_OK = 1; private static final byte STATUS_UNKNOWN = 2; private static final byte STATUS_EXCEPTION = 3;

在這個案例里面 , 游標(biāo)本身只代表了定位 , 但是它可以配合多個其他的對象 , 來擴展其含義. 同時游標(biāo)可以通過設(shè)置負(fù)數(shù)形式 , 來擴展其狀態(tài)含義. 當(dāng)其等于 -1 時 , 則標(biāo)識不存在該對象 , 是另外一種層面的擴展
總結(jié)
對數(shù)據(jù)的信息處理其實還有很多種方式 , 總結(jié)出來主要包括以下幾種 :
- 簡單的通過其遞增的變化 , 來對應(yīng)不同的狀態(tài)
- 通過數(shù)字的疊加 , 來記錄多種狀態(tài)的疊加
- 通過二進制內(nèi)不同的位數(shù) , 來記錄多種層面的數(shù)據(jù)
- 通過 long 等長位數(shù) , 來為不同的位數(shù)匹配不同的含義
- 通過作為一個游標(biāo) ,配合其他的對象做更深度的擴展
到此這篇關(guān)于詳解Java如何利用數(shù)字描述更多的信息的文章就介紹到這了,更多相關(guān)Java描述信息內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot日志進階實戰(zhàn)之Logback配置經(jīng)驗和方法
本文給大家介紹在SpringBoot中使用Logback配置日志的經(jīng)驗和方法,并提供了詳細(xì)的代碼示例和解釋,包括:滾動文件、異步日志記錄、動態(tài)指定屬性、日志級別、配置文件等常用功能,覆蓋日常Logback配置開發(fā)90%的知識點,感興趣的朋友跟隨小編一起看看吧2023-06-06
SpringBoot AOP注解失效問題排查與解決(調(diào)用內(nèi)部方法)
這篇文章主要介紹了SpringBoot AOP注解失效問題排查與解決(調(diào)用內(nèi)部方法),文中通過代碼示例介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-04-04
詳解Java中Checked Exception與Runtime Exception 的區(qū)別
這篇文章主要介紹了詳解Java中Checked Exception與Runtime Exception 的區(qū)別的相關(guān)資料,這里提供實例幫助大家學(xué)習(xí)理解這部分內(nèi)容,需要的朋友可以參考下2017-08-08
RocketMQ?broker?消息投遞流程處理PULL_MESSAGE請求解析
這篇文章主要為大家介紹了RocketMQ?broker?消息投遞流程處理PULL_MESSAGE請求源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-04-04

