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