天天看點

Java并發程式設計中自旋鎖會浪費 CPU 資源并導緻錯誤

在并發程式設計中,自旋鎖(spin locks )想必大家都不陌生。

自旋鎖一個非常經典的使用場景是CAS(即比較和交換),是一種無鎖的思想(說白了就是使用了無限循環),用來解決更新資料的問題高并發場景。

atomic包下的很多類,如AtomicInteger、AtomicLong、AtomicBoolean等,都是用CAS實作的。

我們以AtomicInteger類為例,它incrementAndGet不會每次都給變量加 1。

<b>public</b> <b>final</b> <b>int</b> incrementAndGet() {
    <b>return</b> unsafe.getAndAddInt(<b>this</b>, valueOffset, 1) + 1;
}      

它的底層是用自旋鎖實作的:

<b>public</b> <b>final</b> <b>int</b> getAndAddInt(Object <b>var</b>1, <b>long</b> <b>var</b>2, <b>int</b> <b>var</b>4) {
  <b>int</b> <b>var</b>5;
  <b>do</b> {
      <b>var</b>5 = <b>this</b>.getIntVolatile(<b>var</b>1, <b>var</b>2);
  } <b>while</b>(!<b>this</b>.compareAndSwapInt(<b>var</b>1, <b>var</b>2, <b>var</b>5, <b>var</b>5 + <b>var</b>4));

    <b>return</b> <b>var</b>5;
}      

在do…while無限循環中,不斷地進行資料的比較和交換。如果一直失敗,就會一直重試。

在高并發的情況下,compareAndSwapInt大機率會失敗,進而導緻CPU不斷自旋,嚴重浪費CPU資源。

那麼,如果這個問題解決了呢?

<b>private</b> <b>boolean</b> compareAndSwapInt2(Object <b>var</b>1, <b>long</b> <b>var</b>2, <b>int</b> <b>var</b>4, <b>int</b> <b>var</b>5) {
     <b>if</b>(<b>this</b>.compareAndSwapInt(<b>var</b>1,<b>var</b>2,<b>var</b>4, <b>var</b>5)) {
          <b>return</b> <b>true</b>;
      } <b>else</b> {
          LockSupport.parkNanos(10);
          <b>return</b> false;
      }
 }      

繼續閱讀