掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
本文轉(zhuǎn)載自微信公眾號(hào)「潛行前行」,作者cscw 。轉(zhuǎn)載本文請(qǐng)聯(lián)系潛行前行公眾號(hào)。

成都創(chuàng)新互聯(lián)是一家專注于成都網(wǎng)站制作、做網(wǎng)站與策劃設(shè)計(jì),涇縣網(wǎng)站建設(shè)哪家好?成都創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)十余年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:涇縣等地區(qū)。涇縣做網(wǎng)站價(jià)格咨詢:18982081108
前言
在使用多線程并發(fā)編程的時(shí),經(jīng)常會(huì)遇到對(duì)共享變量修改操作。此時(shí)我們可以選擇ConcurrentHashMap,ConcurrentLinkedQueue來(lái)進(jìn)行安全地存儲(chǔ)數(shù)據(jù)。但如果單單是涉及狀態(tài)的修改,線程執(zhí)行順序問(wèn)題,使用Atomic開(kāi)頭的原子組件或者ReentrantLock、CyclicBarrier之類的同步組件,會(huì)是更好的選擇,下面將一一介紹它們的原理和用法
原子組件的實(shí)現(xiàn)原理CAS
應(yīng)用場(chǎng)景
原子組件
基本類型原子類
- AtomicBoolean //布爾類型
- AtomicInteger //正整型數(shù)類型
- AtomicLong //長(zhǎng)整型類型
使用示例
- public static void main(String[] args) throws Exception {
- AtomicBoolean atomicBoolean = new AtomicBoolean(false);
- //異步線程修改atomicBoolean
- CompletableFuture
future = CompletableFuture.runAsync(() ->{ - try {
- Thread.sleep(1000); //保證異步線程是在主線程之后修改atomicBoolean為false
- atomicBoolean.set(false);
- }catch (Exception e){
- throw new RuntimeException(e);
- }
- });
- atomicBoolean.set(true);
- future.join();
- System.out.println("boolean value is:"+atomicBoolean.get());
- }
- ---------------輸出結(jié)果------------------
- boolean value is:false
引用類原子類
- AtomicReference
- //加時(shí)間戳版本的引用類原子類
- AtomicStampedReference
- //相當(dāng)于AtomicStampedReference,AtomicMarkableReference關(guān)心的是
- //變量是否還是原來(lái)變量,中間被修改過(guò)也無(wú)所謂
- AtomicMarkableReference
- public class AtomicReference
implements java.io.Serializable { - private static final long serialVersionUID = -1848883965231344442L;
- private static final VarHandle VALUE;
- static {
- try {
- MethodHandles.Lookup l = MethodHandles.lookup();
- VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
- } catch (ReflectiveOperationException e) {
- throw new ExceptionInInitializerError(e);
- }
- }
- private volatile V value;
- ....
ABA問(wèn)題
- public class AtomicStampedReference
{ - private static class Pair
{ - final T reference;
- final int stamp;
- private Pair(T reference, int stamp) {
- this.reference = reference;
- this.stamp = stamp;
- }
- static
Pair of(T reference, int stamp) { - return new Pair
(reference, stamp); - }
- }
- private volatile Pair
pair;
- public class Main {
- public static void main(String[] args) throws Exception {
- Test old = new Test("hello"), newTest = new Test("world");
- AtomicStampedReference
reference = new AtomicStampedReference<>(old, 1); - reference.compareAndSet(old, newTest,1,2);
- System.out.println("對(duì)象:"+reference.getReference().name+";版本號(hào):"+reference.getStamp());
- }
- }
- class Test{
- Test(String name){ this.name = name; }
- public String name;
- }
- ---------------輸出結(jié)果------------------
- 對(duì)象:world;版本號(hào):2
數(shù)組原子類
- AtomicIntegerArray //整型數(shù)組
- AtomicLongArray //長(zhǎng)整型數(shù)組
- AtomicReferenceArray //引用類型數(shù)組
- //元素默認(rèn)初始化為0
- AtomicIntegerArray array = new AtomicIntegerArray(2);
- // 下標(biāo)為0的元素,期待值是0,更新值是1
- array.compareAndSet(0,0,1);
- System.out.println(array.get(0));
- ---------------輸出結(jié)果------------------
- 1
屬性原子類
- AtomicIntegerFieldUpdater
- AtomicLongFieldUpdater
- AtomicReferenceFieldUpdater
- public class Main {
- public static void main(String[] args) {
- AtomicReferenceFieldUpdater
fieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Test.class,String.class,"name"); - Test test = new Test("hello world");
- fieldUpdater.compareAndSet(test,"hello world","siting");
- System.out.println(fieldUpdater.get(test));
- System.out.println(test.name);
- }
- }
- class Test{
- Test(String name){ this.name = name; }
- public volatile String name;
- }
- ---------------輸出結(jié)果------------------
- siting
- siting
累加器
- Striped64
- LongAccumulator
- LongAdder
- //accumulatorFunction:運(yùn)算規(guī)則,identity:初始值
- public LongAccumulator(LongBinaryOperator accumulatorFunction,long identity)
- public static void main(String[] args) throws Exception {
- LongAccumulator accumulator = new LongAccumulator(Long::sum, 0);
- for(int i=0;i<100000;i++){
- CompletableFuture.runAsync(() -> accumulator.accumulate(1));
- }
- Thread.sleep(1000); //等待全部CompletableFuture線程執(zhí)行完成,再獲取
- System.out.println(accumulator.get());
- }
- ---------------輸出結(jié)果------------------
- 100000
同步組件的實(shí)現(xiàn)原理
java的多數(shù)同步組件會(huì)在內(nèi)部維護(hù)一個(gè)狀態(tài)值,和原子組件一樣,修改狀態(tài)值時(shí)一般也是通過(guò)cas來(lái)實(shí)現(xiàn)。而狀態(tài)修改的維護(hù)工作被Doug Lea抽象出AbstractQueuedSynchronizer(AQS)來(lái)實(shí)現(xiàn)
AQS的原理可以看下之前寫的一篇文章:詳解鎖原理,synchronized、volatile+cas底層實(shí)現(xiàn)[2]
同步組件
ReentrantLock、ReentrantReadWriteLock
- ReentrantLock lock = new ReentrantLock();
- if(lock.tryLock()){
- //業(yè)務(wù)邏輯
- lock.unlock();
- }
- public static void main(String[] args) throws Exception {
- ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
- if(lock.readLock().tryLock()){ //讀鎖
- //業(yè)務(wù)邏輯
- lock.readLock().unlock();
- }
- if(lock.writeLock().tryLock()){ //寫鎖
- //業(yè)務(wù)邏輯
- lock.writeLock().unlock();
- }
- }
Semaphore實(shí)現(xiàn)原理和使用場(chǎng)景
- public static void main(String[] args) throws Exception {
- Semaphore semaphore = new Semaphore(2);
- for (int i = 0; i < 3; i++)
- CompletableFuture.runAsync(() -> {
- try {
- System.out.println(Thread.currentThread().toString() + " start ");
- if(semaphore.tryAcquire(1)){
- Thread.sleep(1000);
- semaphore.release(1);
- System.out.println(Thread.currentThread().toString() + " 無(wú)阻塞結(jié)束 ");
- }else {
- System.out.println(Thread.currentThread().toString() + " 被阻塞結(jié)束 ");
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
- //保證CompletableFuture 線程被執(zhí)行,主線程再結(jié)束
- Thread.sleep(2000);
- }
- ---------------輸出結(jié)果------------------
- Thread[ForkJoinPool.commonPool-worker-19,5,main] start
- Thread[ForkJoinPool.commonPool-worker-5,5,main] start
- Thread[ForkJoinPool.commonPool-worker-23,5,main] start
- Thread[ForkJoinPool.commonPool-worker-23,5,main] 被阻塞結(jié)束
- Thread[ForkJoinPool.commonPool-worker-5,5,main] 無(wú)阻塞結(jié)束
- Thread[ForkJoinPool.commonPool-worker-19,5,main] 無(wú)阻塞結(jié)束
可以看出三個(gè)線程,因?yàn)樾盘?hào)量設(shè)定為2,第三個(gè)線程是無(wú)法獲取信息成功的,會(huì)打印阻塞結(jié)束
CountDownLatch實(shí)現(xiàn)原理和使用場(chǎng)景
- public static void main(String[] args) throws Exception {
- CountDownLatch count = new CountDownLatch(2);
- for (int i = 0; i < 2; i++)
- CompletableFuture.runAsync(() -> {
- try {
- Thread.sleep(1000);
- System.out.println(" CompletableFuture over ");
- count.countDown();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
- //等待CompletableFuture線程的完成
- count.await();
- System.out.println(" main over ");
- }
- ---------------輸出結(jié)果------------------
- CompletableFuture over
- CompletableFuture over
- main over
CyclicBarrier實(shí)現(xiàn)原理和使用場(chǎng)景
- public static void main(String[] args) throws Exception {
- CyclicBarrier barrier = new CyclicBarrier(2);
- CompletableFuture.runAsync(()->{
- try {
- System.out.println("CompletableFuture run start-"+ Clock.systemUTC().millis());
- barrier.await(); //需要等待main線程也執(zhí)行到await狀態(tài)才能繼續(xù)執(zhí)行
- System.out.println("CompletableFuture run over-"+ Clock.systemUTC().millis());
- }catch (Exception e){
- throw new RuntimeException(e);
- }
- });
- Thread.sleep(1000);
- //和CompletableFuture線程相互等待
- barrier.await();
- System.out.println("main run over!");
- }
- ---------------輸出結(jié)果------------------
- CompletableFuture run start-1609822588881
- main run over!
- CompletableFuture run over-1609822589880
StampedLock
- //獲取讀鎖,自旋獲取,返回一個(gè)戳值
- public long readLock()
- //嘗試加讀鎖,不成功返回0
- public long tryReadLock()
- //解鎖
- public void unlockRead(long stamp)
- //獲取寫鎖,自旋獲取,返回一個(gè)戳值
- public long writeLock()
- //嘗試加寫鎖,不成功返回0
- public long tryWriteLock()
- //解鎖
- public void unlockWrite(long stamp)
- //嘗試樂(lè)觀讀讀取一個(gè)時(shí)間戳,并配合validate方法校驗(yàn)時(shí)間戳的有效性
- public long tryOptimisticRead()
- //驗(yàn)證stamp是否有效
- public boolean validate(long stamp)
- public static void main(String[] args) throws Exception {
- StampedLock stampedLock = new StampedLock();
- long stamp = stampedLock.tryOptimisticRead();
- //判斷版本號(hào)是否生效
- if (!stampedLock.validate(stamp)) {
- //獲取讀鎖,會(huì)空轉(zhuǎn)
- stamp = stampedLock.readLock();
- long writeStamp = stampedLock.tryConvertToWriteLock(stamp);
- if (writeStamp != 0) { //成功轉(zhuǎn)為寫鎖
- //fixme 業(yè)務(wù)操作
- stampedLock.unlockWrite(writeStamp);
- } else {
- stampedLock.unlockRead(stamp);
- //嘗試獲取寫讀
- stamp = stampedLock.tryWriteLock();
- if (stamp != 0) {
- //fixme 業(yè)務(wù)操作
- stampedLock.unlockWrite(writeStamp);
- }
- }
- }
- }
參考文章
參考資料
[1]詳解鎖原理,synchronized、volatile+cas底層實(shí)現(xiàn): https://juejin.cn/post/6854573210768900110
[2]詳解鎖原理,synchronized、volatile+cas底層實(shí)現(xiàn): https://juejin.cn/post/6854573210768900110
[3]并發(fā)之Striped64(l累加器): https://www.cnblogs.com/gosaint/p/9129867.html

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問(wèn)/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流