1. 程式人生 > >一段JAVA代碼了解多線程,JUC、CAS原子性操作。

一段JAVA代碼了解多線程,JUC、CAS原子性操作。

current 排序 沒有 共享數據 信號 call countdown for ride

  @Test
    public void testPaceController_multiThread() throws InterruptedException {
        final PaceController paceController = new PaceController(1000, 160d);
        final Node node = mock(Node.class);

        final AtomicInteger passcount = new AtomicInteger();
        final AtomicInteger blockcount = new
AtomicInteger(); final AtomicInteger done = new AtomicInteger(); AtomicLong lastTm = new AtomicLong(System.currentTimeMillis() / 1000); int count = 1000; final CountDownLatch countDown = new CountDownLatch(count); for (int i = 0; i < count; i++) { Thread thread
= new Thread(new Runnable() { @Override public void run() { for(int j =0; j< 10; j++) { boolean pass = paceController.canPass(node, 1).isPass(); if (pass == true) { passcount.incrementAndGet(); }
else { blockcount.incrementAndGet(); } done.incrementAndGet(); long now = System.currentTimeMillis() / 1000; if (lastTm.get() != now) { System.out.println("pass:" + passcount.get() + ", tm:" + lastTm.get()); System.out.println("block:" + blockcount.get() + ", tm:" + lastTm.get()); System.out.println("done:" + done.get() + ", tm:" + lastTm.get()); passcount.set(0); blockcount.set(0); done.set(0); } lastTm.set(now); } countDown.countDown(); } }, "Thread " + i); thread.start(); } countDown.await(); System.out.println("pass:" + passcount.get() + ", tm:" + lastTm.get()); System.out.println("block:" + blockcount.get() + ", tm:" + lastTm.get()); System.out.println("done:" + done.get() + ", tm:" + lastTm.get()); }
1.CountDownLatch 同步並發處理
countDown.countDown 遞減為0,等待發射信號。

countDown.await()阻塞當前線程,等待調用。

2.AtomicInteger 和 volatile 的區別,CAS原子性操作。

volatile關鍵字很重要的兩個特性:

1、保證變量在線程間可見,對volatile變量所有的寫操作都能立即反應到其他線程中,換句話說,volatile變量在各個線程中是一致的(得益於java內存模型—"先行發生原則");

2、禁止指令的重排序優化;

所以volatile 並非原子性操作。

AtomicInteger非阻塞同步(原子性CAS)

同步:多線程並發訪問共享數據時,保證共享數據再同一時刻只被一個或一些線程使用。

我們知道,阻塞同步和非阻塞同步都是實現線程安全的兩個保障手段,非阻塞同步對於阻塞同步而言主要解決了阻塞同步中線程阻塞和喚醒帶來的性能問題,那什麽叫做非阻塞同步呢?在並發環境下,某個線程對共享變量先進行操作,如果沒有其他線程爭用共享數據那操作就成功;如果存在數據的爭用沖突,那就才去補償措施,比如不斷的重試機制,直到成功為止,因為這種樂觀的並發策略不需要把線程掛起,也就把這種同步操作稱為非阻塞同步(操作和沖突檢測具備原子性)。在硬件指令集的發展驅動下,使得 "操作和沖突檢測" 這種看起來需要多次操作的行為只需要一條處理器指令便可以完成,這些指令中就包括非常著名的CAS指令(Compare-And-Swap比較並交換)。《深入理解Java虛擬機第二版.周誌明》第十三章中這樣描述關於CAS機制:


圖取自《深入理解Java虛擬機第二版.周誌明》13.2.2
所以再返回來看AtomicInteger.incrementAndGet()方法,它的時間也比較簡單

/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
  return next;
}
}


incrementAndGet()方法在一個無限循環體內,不斷嘗試將一個比當前值大1的新值賦給自己,如果失敗則說明在執行"獲取-設置"操作的時已經被其它線程修改過了,於是便再次進入循環下一次操作,直到成功為止。這個便是AtomicInteger原子性的"訣竅"了,繼續進源碼看它的compareAndSet方法:

/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
  return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

可以看到,compareAndSet()調用的就是Unsafe.compareAndSwapInt()方法,即Unsafe類的CAS操作。

一段JAVA代碼了解多線程,JUC、CAS原子性操作。