1. 程式人生 > 其它 >演算法~如何將整數按著型別分段

演算法~如何將整數按著型別分段

如何將整數按著型別分段,即有個數字3,它可以表示型別1裡的計數3;有個數字10005,它可以表求型別2裡的5,這種設計主要用在型別和數字關係緊密的場景,向ThreadPoolExecutor用到了這種設計,ThreadPoolExecutor中的runState和workCount機制,實現在一個int變數中,儲存這兩種資訊,如何實現的?`

位運算基礎

位運算保證的運算的結果是2的n次冪

// i = 10: 十進位制 是10,二進位制是 1010
// i << 1: 左移1位,二進位制變為 10100,轉換位十進位制 則是 20,相當於乘以2的1次數
// i = 20: 十進位制 是20,二進位制是 10100
// i >> 1: 右移1位,二進位制變為 1010,轉換位十進位制 則是 10,相當於除以2的1次數
// i << 3:相當於乘以2的3次方;i >> 3:相當於除以2的3次數
  • 使用程式碼進行說明
@Slf4j
public class BitTest {
  private static final int COUNT_BITS = Integer.SIZE - 3;
  // 低29位的容量
  private static final int CAPACITY = (1 << COUNT_BITS) - 1;
  // 把runState理解為區間段,每個區間段都有獨立的workCount,它們都是成對出現的
  private static final int RUNNING = -1 << COUNT_BITS;//-1*536,870,912
  private static final int SHUTDOWN = 0 << COUNT_BITS; //0*536,870,912=0
  private static final int STOP = 1 << COUNT_BITS; //1*536,870,912
  private static final int TIDYING = 2 << COUNT_BITS;//2*536,870,912
  private static final int TERMINATED = 3 << COUNT_BITS;//3*536,870,912
  private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

  // 執行狀態[高3位]
  private static int runStateOf(int c) {
    return c & ~CAPACITY;
  }

  // 工作數[低29位]
  private static int workerCountOf(int c) {
    return c & CAPACITY;
  }

  // 狀態和工作數生成的ctl,是一個數字,每個區間段通過runState來區分
  private static int ctlOf(int rs, int wc) {
    return rs | wc;
  }

  /**
   * 一個數,存兩個狀態的值,高3位存runState,低29位儲存workCount
   */
  @Test
  public void runStateWorkCount() {
   
    //閾值,將一個int32的資料分成了幾個區間段,而這個狀態值與遞增數的臨界點就是cap,如int32的低10位存遞增,高22位存狀態
    int cap = Integer.SIZE - 22;//10
    cap=(1 << cap) - 1; //向左移10位減1,到了高22位
    //狀態數
    int status = 1 << cap; //第一個區間段,可以從0開始的
    //遞增數
    int indexCount = 5;
    log.debug("-------------------------------------------");
    int saveValue=ctlOf(indexCount, status);
    log.debug("需要持久化的數:{} | {}={}", indexCount, status, saveValue);
    log.debug("獲取狀態數:{},獲取對應的遞增數:{}", runStateOf(saveValue),workerCountOf(saveValue));
    log.debug("-------------------------------------------");
    ctl.set(ctlOf(RUNNING, 256));
    log.debug("ctl={}", ctl.get());
    System.out.println("runStateOf=" + runStateOf(ctl.get()));
    System.out.println("workerCountOf=" + workerCountOf(ctl.get()));

  }
}

  • 結果
14:05:19.107 [main] DEBUG com.lind.common.aesh.command.BitTest - -2147483648 & ~1023=-2147483648
14:05:19.111 [main] DEBUG com.lind.common.aesh.command.BitTest - 5 & 1023=5
14:05:19.111 [main] DEBUG com.lind.common.aesh.command.BitTest - -------------------------------------------
14:05:19.111 [main] DEBUG com.lind.common.aesh.command.BitTest - 需要持久化的數:5 | -2147483648=-2147483643
14:05:19.111 [main] DEBUG com.lind.common.aesh.command.BitTest - 獲取狀態數:-2147483648,獲取對應的遞增數:5
14:05:19.111 [main] DEBUG com.lind.common.aesh.command.BitTest - -------------------------------------------
14:05:19.111 [main] DEBUG com.lind.common.aesh.command.BitTest - ctl=-536870656
  • 結論
    將我們的數字分成了若干的區間,通過位運算計算這個數,並存儲這個數及解析這個數