最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java CAS基本實(shí)現(xiàn)原理代碼實(shí)例解析

 更新時(shí)間:2020年07月31日 10:07:06   作者:與李  
這篇文章主要介紹了Java CAS基本實(shí)現(xiàn)原理代碼實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

一、前言

了解CAS,首先要清楚JUC,那么什么是JUC呢?JUC就是java.util.concurrent包的簡(jiǎn)稱。它有核心就是CAS與AQS。CAS是java.util.concurrent.atomic包的基礎(chǔ),如AtomicInteger、AtomicBoolean、AtomicLong等等類都是基于CAS。

什么是CAS呢?全稱Compare And Swap,比較并交換。CAS有三個(gè)操作數(shù),內(nèi)存值V,舊的預(yù)期值E,要修改的新值N。當(dāng)且僅當(dāng)預(yù)期值E和內(nèi)存值V相同時(shí),將內(nèi)存值V修改為N,否則什么都不做。

二、實(shí)例

如果我們需要對(duì)一個(gè)數(shù)進(jìn)行加法操作,應(yīng)該怎樣去實(shí)現(xiàn)呢?我們模擬多個(gè)線程情況下進(jìn)行操作。

ThreadDemo.java 實(shí)現(xiàn)一個(gè)Runnable接口

package com.spring.security.test;

public class ThreadDemo implements Runnable {

	private int count = 0;

	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			addCount();
		}
	}

	private void addCount() {
		count++;
	}

	public int getCount() {
		return count;
	}
}

ThreadTest.java 創(chuàng)建線程池,提交10個(gè)線程執(zhí)行,預(yù)期結(jié)果應(yīng)該是1000

package com.spring.security.test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadTest {
	public static void main(String[] args) {
		ExecutorService threadPool = Executors.newFixedThreadPool(10);
		ThreadDemo threadDemo = new ThreadDemo();
		for (int i = 0; i < 10; i++) {
			threadPool.submit(threadDemo);
		}
    threadPool.shutdown();
		System.out.println(threadDemo.getCount());
	}
}

運(yùn)行結(jié)果:874 或其他,與預(yù)期結(jié)果不符合。

執(zhí)行出來的結(jié)果并不是想象中的結(jié)果。這是為什么呢?這跟線程的執(zhí)行過程有關(guān)。

所以我們需要在改變count,將值從高速緩沖區(qū)刷新到主內(nèi)存后,讓其他線程重新讀取主內(nèi)存中的值到自己的工作內(nèi)存。

此時(shí)可以用volatile關(guān)鍵字。它的作用是保證對(duì)象在內(nèi)存中的可見性。

修改ThreadDemo中的count字段

private volatile int count = 0;

此時(shí)執(zhí)行結(jié)果:900 或其他,與預(yù)期結(jié)果不符合。

此時(shí)還是并未得出正確執(zhí)行結(jié)果。為什么?聽我細(xì)細(xì)道來。

線程安全主要體現(xiàn)在三個(gè)方面:

  • 原子性:提供了互斥訪問,同一時(shí)刻只能有一個(gè)線程對(duì)它進(jìn)行操作
  • 可見性:一個(gè)線程對(duì)主內(nèi)存的修改可以及時(shí)的被其他線程觀察到
  • 有序性:一個(gè)線程觀察其他線程中的指令執(zhí)行順序,由于指令重排序的存在,該觀察結(jié)果一般雜亂無序

目前可見性已經(jīng)實(shí)現(xiàn)了,缺少原子性的操作,因?yàn)橥粫r(shí)刻,多個(gè)線程對(duì)其操作,會(huì)將改動(dòng)后的最新值讀取到自己的工作內(nèi)存進(jìn)行操作,最終只能得到后一個(gè)執(zhí)行線程操作的結(jié)果,所以相當(dāng)于少了一步操作,就會(huì)造成數(shù)據(jù)的不一致。

此時(shí)可以使用JUC的Atomic包下面的類來進(jìn)行操作。

Atomic類是使用CAS+volatile來實(shí)現(xiàn)原子性與可見性的。

我們來改造一下TheadDemo.java中的實(shí)現(xiàn)方法

package com.spring.security.test;

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadDemo implements Runnable {

	private AtomicInteger count = new AtomicInteger(0);

	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			// 遞增
			count.getAndIncrement();
		}
	}

	public int getCount() {
		return count.get();
	}
}

執(zhí)行結(jié)果: 1000,符合預(yù)期值。

接下來我們來分析一下AtomicInteger類的源碼:

private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;

static {
  try {
    valueOffset = unsafe.objectFieldOffset
      (AtomicInteger.class.getDeclaredField("value"));
  } catch (Exception ex) { throw new Error(ex); }
}

private volatile int value;

Unsafe類是不安全的類,它提供了一些底層的方法,我們是不能使用這個(gè)類的。AtomicInteger的值保存在value中,而valueOffset是value在內(nèi)存中的偏移量,利用靜態(tài)代碼塊使其類一加載的時(shí)候就賦值。value值使用volatile,保證其可見性。

  /**
   * Atomically increments by one the current value.
   *
   * @return the previous value
   */
  public final int getAndIncrement() {
    return unsafe.getAndAddInt(this, valueOffset, 1);
  }
public final int getAndAddInt(Object var1, long var2, int var4) {
	int var5;
	do {
		var5 = this.getIntVolatile(var1, var2);
	} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

	return var5;
}

var1表示當(dāng)前對(duì)象,var2表示value在內(nèi)存中的偏移量,var4為增加的值。var5為調(diào)用底層方法獲取value的值

compareAndSwapInt方法通過var1和var2獲取當(dāng)前內(nèi)存中的value值,并與var5進(jìn)行比對(duì),如果一致,就將var5+var4的值賦給value,并返回true,否則返回false

由do while語(yǔ)句可知,如果這次沒有設(shè)置進(jìn)去值,就重復(fù)執(zhí)行此過程。這一過程稱為自旋。

compareAndSwapInt是JNI(Java Native Interface)提供的方法,可以是其他語(yǔ)言寫的。

三、與synchronized比較

使用synchronized進(jìn)行加法:

package com.spring.security.test;

public class ThreadDemo implements Runnable {

	private int count = 0;

	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			// 遞增
			synchronized (ThreadDemo.class) {
				count++;
			}
		}
	}

	public int getCount() {
		return count;
	}
}

運(yùn)行結(jié)果: 1000,符合預(yù)期值。

444

使用synchronized和AtomicInteger都能得到預(yù)期結(jié)果,但是他們之間各有什么劣勢(shì)呢?

synchronized是重量級(jí)鎖,是悲觀鎖,就是無論你線程之間發(fā)不發(fā)生競(jìng)爭(zhēng)關(guān)系,它都認(rèn)為會(huì)發(fā)生競(jìng)爭(zhēng),從而每次執(zhí)行都會(huì)加鎖。

在并發(fā)量大的情況下,如果鎖的時(shí)間較長(zhǎng),那將會(huì)嚴(yán)重影響系統(tǒng)性能。

CAS操作中我們可以看到getAndAddInt方法的自旋操作,如果長(zhǎng)時(shí)間自旋,那么肯定會(huì)對(duì)系統(tǒng)造成壓力。而且如果value值從A->B->A,那么CAS就會(huì)認(rèn)為這個(gè)值沒有被操作過,這個(gè)稱為CAS操作的"ABA"問題。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • JAVA中的Token 基于Token的身份驗(yàn)證實(shí)例

    JAVA中的Token 基于Token的身份驗(yàn)證實(shí)例

    這篇文章主要介紹了JAVA中的Token 基于Token的身份驗(yàn)證實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Mybatis日期格式自動(dòng)轉(zhuǎn)換需要用到的兩個(gè)注解說明

    Mybatis日期格式自動(dòng)轉(zhuǎn)換需要用到的兩個(gè)注解說明

    這篇文章主要介紹了Mybatis日期格式自動(dòng)轉(zhuǎn)換需要用到的兩個(gè)注解說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java中的notyfy()和notifyAll()的本質(zhì)區(qū)別

    Java中的notyfy()和notifyAll()的本質(zhì)區(qū)別

    很多朋友對(duì)java中的notyfy()和notifyAll()的本質(zhì)區(qū)別不了解,今天小編抽空給大家整理一篇教程關(guān)于Java中的notyfy()和notifyAll()的本質(zhì)區(qū)別,需要的朋友參考下吧
    2017-02-02
  • SpringBoot中使用@scheduled定時(shí)執(zhí)行任務(wù)的坑

    SpringBoot中使用@scheduled定時(shí)執(zhí)行任務(wù)的坑

    本文主要介紹了SpringBoot中使用@scheduled定時(shí)執(zhí)行任務(wù)的坑,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • Java 三種進(jìn)制的數(shù)值常量操作

    Java 三種進(jìn)制的數(shù)值常量操作

    這篇文章主要介紹了Java 三種進(jìn)制的數(shù)值常量操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 使用java實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲

    使用java實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲

    這篇文章主要介紹了使用java實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • JDBC編程實(shí)現(xiàn)文件、圖片的存儲(chǔ)方法

    JDBC編程實(shí)現(xiàn)文件、圖片的存儲(chǔ)方法

    這篇文章主要介紹了JDBC編程實(shí)現(xiàn)文件、圖片的存儲(chǔ)方法,以實(shí)例形式分析了Java基于JDBC操作數(shù)據(jù)庫(kù)的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • Java用編碼檢測(cè)代理ip是否有效

    Java用編碼檢測(cè)代理ip是否有效

    這篇文章主要為大家詳細(xì)介紹了Java如何使用編碼檢測(cè)代理ip是否有效,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-12-12
  • SpringBoot管理RabbitMQ中的Channel詳解

    SpringBoot管理RabbitMQ中的Channel詳解

    這篇文章主要介紹了SpringBoot管理RabbitMQ中的Channel詳解,channel僅存在于connection的上下文中,而不會(huì)單獨(dú)存在,當(dāng)channel關(guān)閉時(shí),其上的所有channel也會(huì)關(guān)閉,需要的朋友可以參考下
    2023-08-08
  • 一文詳解Java項(xiàng)目中如何優(yōu)雅的使用枚舉類型

    一文詳解Java項(xiàng)目中如何優(yōu)雅的使用枚舉類型

    枚舉類型在開發(fā)中是很常見的,有非常多的應(yīng)用場(chǎng)景,這篇文章我們就來學(xué)習(xí)一下項(xiàng)目中如何優(yōu)雅的使用枚舉類型,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03

最新評(píng)論

日喀则市| 弥渡县| 呼和浩特市| 应城市| 衡阳市| 开鲁县| 望谟县| 宝清县| 斗六市| 宣城市| 阿坝县| 呼玛县| 嘉祥县| 汉中市| 宿迁市| 阿坝县| 彭州市| 额尔古纳市| 阳山县| 田林县| 泸定县| 临桂县| 叙永县| 临清市| 中方县| 十堰市| 文登市| 临海市| 兖州市| 青铜峡市| 昂仁县| 苍梧县| 浦东新区| 英山县| 区。| 大邑县| 缙云县| 龙陵县| 彭泽县| 商水县| 木兰县|