15.JUC原子類

文章目錄

  • JUC原子類
    • 1.JUC中的Atomic原子操作包
      • 1.1. 基本原子類(Basic Atomic Classes)
      • 1.2. 數組原子類(Array Atomic Classes)
      • 1.3. 引用原子類(Reference Atomic Classes)
      • 4. 字段更新原子類(Field Updater Atomic Classes)
    • 2.基礎原子類(Atomic Integer)
      • 2.1.基本方法
      • 2.2.案例代碼
    • 3.數組原子類
      • 3.1.基本方法
      • 3.2.案例代碼
    • 4.AtomicInteger線程安全原理
    • 5.對象操作原子性
      • 5.1引用類型原子類
      • 5.2.案例代碼
    • 6.屬性更新原子類
      • 6.1.屬性更新原子類
      • 6.2.案例代碼

JUC原子類

在多線程并發執行過程中,例如++ ,–,這類運算符都是不具備原子性的,通常我們會使用synchronized將其變為同步操作,但是這樣會導致性能上的下降。JDK為這些不安全的操作提供了一些原子類,JDK原子類基于CAS輕量級原子操作實現,使得運行效率變得很高。

1.JUC中的Atomic原子操作包

Java中的java.util.concurrent.atomic包提供了一系列的原子操作類,用于在多線程環境下進行原子操作。這些類通常用于實現線程安全的計數器、標志位、引用等,并且比使用synchronized關鍵字或者volatile變量實現的方式更高效。

在這里插入圖片描述

根據操作目標的數據類型,可以將JUC包的原子類分為以下4類,基本原子類數組原子類引用原子類字段更新原子類

1.1. 基本原子類(Basic Atomic Classes)

這些類用于對基本數據類型進行原子操作,如int、long、boolean等。

  • AtomicBoolean:提供了對boolean類型值的原子更新操作,使用CAS算法來保證原子性。

    AtomicBoolean atomicBoolean = new AtomicBoolean(true);
    atomicBoolean.getAndSet(false); // 設置新值并返回舊值
    
  • AtomicInteger:提供了對int類型值的原子更新操作,同樣使用CAS算法。

    AtomicInteger atomicInteger = new AtomicInteger(0);
    atomicInteger.incrementAndGet(); // 原子地將當前值加一,并返回增加后的值
    
  • AtomicLong:提供了對long類型值的原子更新操作。

    AtomicLong atomicLong = new AtomicLong(0L);
    atomicLong.compareAndExchange(0L, 1L); // 如果當前值等于預期值,則更新為新值
    

1.2. 數組原子類(Array Atomic Classes)

這些類用于對數組中的元素進行原子操作。

  • AtomicIntegerArray:提供了對int數組中元素的原子更新操作。

    AtomicIntegerArray atomicIntArray = new AtomicIntegerArray(5);
    atomicIntArray.getAndIncrement(0); // 原子地將指定索引位置的元素加一,并返回原值
    
  • AtomicLongArray:提供了對long數組中元素的原子更新操作。

    AtomicLongArray atomicLongArray = new AtomicLongArray(5);
    atomicLongArray.addAndGet(0, 10L); // 原子地將指定索引位置的元素加上給定的值,并返回增加后的值
    
  • AtomicReferenceArray:提供了對引用類型數組中元素的原子更新操作。

    AtomicReferenceArray<String> atomicRefArray = new AtomicReferenceArray<>(new String[]{"a", "b", "c"});
    atomicRefArray.compareAndSet(1, "b", "new_value"); // 如果當前值等于預期值,則更新為新值
    

1.3. 引用原子類(Reference Atomic Classes)

這些類用于對引用類型數據進行原子操作。

  • AtomicReference:提供了對引用類型值的原子更新操作。

    AtomicReference<String> atomicReference = new AtomicReference<>("initial_value");
    atomicReference.getAndSet("new_value"); // 設置新值并返回舊值
    

4. 字段更新原子類(Field Updater Atomic Classes)

這些類用于對指定類的指定字段進行原子更新操作,通常用于性能優化。

  • AtomicIntegerFieldUpdater:用于對指定類的指定volatile int字段進行原子更新操作。

    AtomicIntegerFieldUpdater<MyClass> updater = AtomicIntegerFieldUpdater.newUpdater(MyClass.class, "fieldName");
    updater.incrementAndGet(instance); // 原子地將指定實例的字段值加一,并返回增加后的值
    
  • AtomicLongFieldUpdater:用于對指定類的指定volatile long字段進行原子更新操作。

    AtomicLongFieldUpdater<MyClass> updater = AtomicLongFieldUpdater.newUpdater(MyClass.class, "fieldName");
    updater.compareAndSet(instance, 0L, 1L); // 如果當前值等于預期值,則更新為新值
    
  • AtomicReferenceFieldUpdater:用于對指定類的指定volatile引用字段進行原子更新操作。

    AtomicReferenceFieldUpdater<MyClass, String> updater = AtomicReferenceFieldUpdater.newUpdater(MyClass.class, String.class, "fieldName");
    updater.getAndSet(instance, "new_value"); // 設置新值并返回舊值
    

這些原子類提供了一系列的原子操作方法,可以確保在多線程環境下的操作是線程安全的,避免了使用synchronized關鍵字或者volatile變量所帶來的性能開銷。

2.基礎原子類(Atomic Integer)

2.1.基本方法

  1. get(): 獲取當前的值。
  2. set(int newValue): 設置為指定的值。
  3. getAndSet(int newValue): 設置為指定的值,并返回舊值。
  4. incrementAndGet(): 將當前值加 1,并返回增加后的值。
  5. decrementAndGet(): 將當前值減 1,并返回減少后的值。
  6. getAndIncrement(): 返回當前值,并將其加 1。
  7. getAndDecrement(): 返回當前值,并將其減 1。
  8. compareAndSet(int expect, int update): 如果當前值等于期望值,則設置為新值,并返回 true,否則返回 false。

2.2.案例代碼

通過調用Atomict提供的API 實現了原子性 修改數據

@Test
@DisplayName("測試AtomicInteger")
public void testAtomicInteger() {log.info("當前值: {}", counter.get());counter.set(10);log.info("設置值為 10");int oldValue = counter.getAndSet(20);log.info("舊值: {}, 新值: {}", oldValue, counter.get());log.info("增加后的值: {}", counter.incrementAndGet());log.info("減少后的值: {}", counter.decrementAndGet());oldValue = counter.getAndIncrement();log.info("舊值: {}, 新值: {}", oldValue, counter.get());oldValue = counter.getAndDecrement();log.info("舊值: {}, 新值: {}", oldValue, counter.get());boolean success = counter.compareAndSet(18, 30);log.info("CAS 結果: {}, 當前值: {}", success, counter.get());}

在這里插入圖片描述

上面的操作是在單線程的環境下,下面我通過多線程來實現 數據的一個自增操作

@Test
@DisplayName("多線程實現自增運算")
public void test() throws InterruptedException {ArrayList<Thread> threads = new ArrayList<>();CountDownLatch latch = new CountDownLatch(10);for (int i = 0; i < 10; i++) {threads.add(new Thread(()->{// 每個線程進行 100次自增運算for (int j = 0; j < 100; j++) {counter.incrementAndGet();}latch.countDown();}));}// 全部啟動線程threads.forEach(Thread::start);// 等待全部線程執行結束latch.await();//打印最終結果log.error("10個線程執行自增后的結果為:{}", counter.get());
}

在這里插入圖片描述

3.數組原子類

3.1.基本方法

  1. get(int index): 獲取指定索引處的值。
  2. set(int index, int newValue): 設置指定索引處的值。
  3. getAndSet(int index, int newValue): 設置指定索引處的值,并返回舊值。
  4. incrementAndGet(int index): 將指定索引處的值加 1,并返回增加后的值。
  5. decrementAndGet(int index): 將指定索引處的值減 1,并返回減少后的值。
  6. addAndGet(int index, int delta): 將指定索引處的值加上給定的增量,并返回增加后的值。
  7. compareAndSet(int index, int expect, int update): 如果指定索引處的值等于期望值,則設置為新值,

3.2.案例代碼

// 數組原子類
private static final AtomicIntegerArray array = new AtomicIntegerArray(5);@Test
@DisplayName("測試數組原子類")
public void testAtomicIntegerArray() {// 1. get(int index)log.info("當前數組值: {}", array.toString());// 2. get(int index)log.info("索引為 0 的值: {}", array.get(0));// 3. set(int index, int newValue)array.set(1, 10);log.info("將索引為 1 的值設置為 10");// 4. getAndSet(int index, int newValue)int oldValue = array.getAndSet(2, 20);log.info("索引為 2 的舊值: {}, 新值: {}", oldValue, array.get(2));// 5. incrementAndGet(int index)log.info("索引為 0 的值自增后的值: {}", array.incrementAndGet(0));// 6. decrementAndGet(int index)log.info("索引為 1 的值自減后的值: {}", array.decrementAndGet(1));// 7. addAndGet(int index, int delta)log.info("索引為 2 的值加上 5 后的值: {}", array.addAndGet(2, 5));// 8. compareAndSet(int index, int expect, int update)boolean success = array.compareAndSet(3, 18, 30);log.info("CAS 結果: {}, 當前值: {}", success, array.get(3));
}

運行以上程序,結果如下:

在這里插入圖片描述

4.AtomicInteger線程安全原理

基礎原子類(以AtomicInteger為例),主要是通過CAS自旋 + volatile相結合的方案實現,既保證了變量操作線程的原子性,有避免了synchronized重量級鎖的開銷,使得Java程序的效率得到大幅度提升。

下面簡單 以AtomicInteger源碼 分析一下 原子類的CAS自旋 + volatile相結合的方案(JDK 17發生 了變化)

public class AtomicInteger extends Number implements java.io.Serializable {private static final long serialVersionUID = 6214790243416807050L;// 使用Unsafe類獲取Unsafe實例,用于執行CAS操作private static final Unsafe U = Unsafe.getUnsafe();// VALUE字段的偏移量private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");// 使用volatile關鍵字保證多線程間的可見性private volatile int value;// 構造方法,初始化AtomicInteger的值public AtomicInteger(int initialValue) {value = initialValue;}// 構造方法,默認初始值為0public AtomicInteger() {}// 獲取當前值public final int get() {return value;}// 設置新值public final void set(int newValue) {value = newValue;}// 延遲設置新值,使用setRelease方法public final void lazySet(int newValue) {U.putIntRelease(this, VALUE, newValue);}// 獲取并設置新值,返回舊值public final int getAndSet(int newValue) {return U.getAndSetInt(this, VALUE, newValue);}// 比較并設置新值,如果當前值等于期望值,則設置為新值,返回設置前的值public final boolean compareAndSet(int expectedValue, int newValue) {return U.compareAndSetInt(this, VALUE, expectedValue, newValue);}// 下面的方法實現了自增、自減、加法運算,并返回相應的結果,以及更新當前值的功能,使用CAS操作保證原子性// 自增并獲取當前值public final int getAndIncrement() {return U.getAndAddInt(this, VALUE, 1);}// 自減并獲取當前值public final int getAndDecrement() {return U.getAndAddInt(this, VALUE, -1);}// 加上指定的值并獲取當前值public final int getAndAdd(int delta) {return U.getAndAddInt(this, VALUE, delta);}// 自增并獲取更新后的值public final int incrementAndGet() {return U.getAndAddInt(this, VALUE, 1) + 1;}// 自減并獲取更新后的值public final int decrementAndGet() {return U.getAndAddInt(this, VALUE, -1) - 1;}// 加上指定的值并獲取更新后的值public final int addAndGet(int delta) {return U.getAndAddInt(this, VALUE, delta) + delta;}// 下面的方法為類型轉換方法,用于轉換為其他基本數據類型// 返回int值public final String toString() {return Integer.toString(get());}// 返回當前值的int表示public int intValue() {return get();}// 返回當前值的long表示public long longValue() {return (long)get();}// 返回當前值的float表示public float floatValue() {return (float)get();}// 返回當前值的double表示public double doubleValue() {return (double)get();}// JDK 9之后的新增方法,使用plain、opaque、acquire、release等方法增加了對內存操作的控制// 返回當前值,使用非volatile內存語義public final int getPlain() {return U.getInt(this, VALUE);}// 設置新值,使用非volatile內存語義public final void setPlain(int newValue) {U.putInt(this, VALUE, newValue);}// 返回當前值,使用opaque內存語義public final int getOpaque() {return U.getIntOpaque(this, VALUE);}// 設置新值,使用opaque內存語義public final void setOpaque(int newValue) {U.putIntOpaque(this, VALUE, newValue);}// 返回當前值,使用acquire內存語義public final int getAcquire() {return U.getIntAcquire(this, VALUE);}// 設置新值,使用release內存語義public final void setRelease(int newValue) {U.putIntRelease(this, VALUE, newValue);}// 使用compareAndExchange方法實現CAS操作,設置新值,返回舊值public final int compareAndExchange(int expectedValue, int newValue) {return U.compareAndExchangeInt(this, VALUE, expectedValue, newValue);}// 使用compareAndExchangeAcquire方法實現CAS操作,設置新值,返回舊值public final int compareAndExchangeAcquire(int expectedValue, int newValue) {return U.compareAndExchangeIntAcquire(this, VALUE, expectedValue, newValue);}// 使用compareAndExchangeRelease方法實現CAS操作,設置新值,返回舊值public final int compareAndExchangeRelease(int expectedValue, int newValue) {return U.compareAndExchangeIntRelease(this, VALUE, expectedValue, newValue);}// 使用weakCompareAndSetInt方法實現CAS操作,設置新值,返回操作是否成功public final boolean weakCompareAndSetVolatile(int expectedValue, int newValue) {return U.weakCompareAndSetInt(this, VALUE, expectedValue, newValue);}// 使用weakCompareAndSetIntAcquire方法實現CAS操作,設置新值,返回操作是否成功public final boolean weakCompareAndSetAcquire(int expectedValue, int newValue) {return U.weakCompareAndSetIntAcquire(this, VALUE, expectedValue, newValue);}// 使用weakCompareAndSetIntRelease方法實現CAS操作,設置新值,返回操作是否成功public final boolean weakCompareAndSetRelease(int expectedValue, int newValue) {return U.weakCompareAndSetIntRelease(this, VALUE, expectedValue, newValue);}
}// 其中自旋操作在UnSafe中實現 /*** Atomically adds the given value to the current value of a field* or array element within the given object {@code o}* at the given {@code offset}.** @param o object/array to update the field/element in* @param offset field/element offset* @param delta the value to add* @return the previous value* @since 1.8*/@IntrinsicCandidatepublic final int getAndAddInt(Object o, long offset, int delta) {int v;do {v = getIntVolatile(o, offset);} while (!weakCompareAndSetInt(o, offset, v, v + delta));return v;}@IntrinsicCandidatepublic native int     getIntVolatile(Object o, long offset);// 比較期望值 并設置@IntrinsicCandidatepublic final boolean weakCompareAndSetInt(Object o, long offset,int expected,int x) {return compareAndSetInt(o, offset, expected, x);}

5.對象操作原子性

基礎原子類型 只能保證一個變量的原子操作,但是當需要對多個變量操作時,CAS無法保證原子性操作,這個時候可以使用AtomicReference(原子引用類型),保證對象引用的原子性。

簡單來說,如果需要同時保證多個變量操作原子性,可以把多個變量放入一個對象中進行操作

5.1引用類型原子類

  • AtomicReference :基礎引用原子類

    • get():獲取當前存儲在AtomicReference中的對象。
    • set():設置AtomicReference中的對象為指定值。
    • compareAndSet():如果當前存儲在AtomicReference中的對象等于預期值,則將AtomicReference中的對象設置為新值。
    • getAndSet():獲取當前存儲在AtomicReference中的對象,并設置AtomicReference中的對象為新值。
  • AtomicStampedReference:原子更新帶有整數標記的引用。此類可以用于解決CAS操作的ABA問題。ABA問題是指在使用CAS進行原子更新時,如果被更新的數據從A變成了B,然后又變回了A,這樣的狀態變化可能會導致誤判。AtomicStampedReference通過引入版本號(或時間戳)來解決這個問題,它將每次更新都與一個標記相關聯,以便在比較時不僅考慮引用對象的值,還要考慮其標記。

    主要方法:

    • boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp):如果當前引用和標記都與預期值匹配,則原子地將引用和標記的值設置為新值。
  • AtomicMarkableReference:原子更新帶有標記位的引用。與AtomicStampedReference類似,但是標記是一個布爾值,只有兩種狀態(true或false)。這個類通常用于簡單的標記,而不需要額外的版本信息。

    主要方法:

    • boolean compareAndSet(V expectedReference, V newReference, boolean expectedMark, boolean newMark):如果當前引用和標記都與預期值匹配,則原子地將引用和標記的值設置為新值。

下面主要介紹一下AtomicReference

5.2.案例代碼

    @Test@DisplayName("測試基礎引用原子類型")public void test2() {// 創建一個初始值為null的AtomicReference對象AtomicReference<Student> atomicReference = new AtomicReference<>(null);Student student = new Student("張三",21);// 設置AtomicReference中的對象值為atomicReference.set(student);log.error("當前AtomicReference中的對象值為: " + atomicReference.get());// 比較并設置操作,如果當前對象值等于"student",則設置為"新的student"boolean success = atomicReference.compareAndSet(student,new Student("李四",21));if (success) {log.error("對象值成功被修改為: " + atomicReference.get());} else {log.error("對象值未被修改,當前值為: " + atomicReference.get());}// 獲取并設置操作,獲取當前對象值并設置為"王五 32"Student studentOld = atomicReference.getAndSet(new Student("王五", 32));log.error("獲取到的舊對象值為: " + studentOld);log.error("當前AtomicReference中的對象值為: " + atomicReference.get());}@Getter@Setter@ToStringclass Student{private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}}

在這里插入圖片描述

注意:使用原子應用類型AtomicReference操作包裝了Student,只能保證Student引用的原子的操作,對被包裝的Student對象的字段修改時并不能保證原子性(說白了,student.setName() 這種是不具備原子性的 new Student(“xxx”,232) 這種 通過包裝統一更新的 是具備原子性的)

6.屬性更新原子類

屬性更新原子類是Java并發包提供的一組類,用于原子性地更新對象中的屬性值。這些類通常用于保證多線程環境下的線程安全性,避免競態條件和數據不一致性問題。

6.1.屬性更新原子類

屬性類更新原子類有以下三個

  1. AtomicIntegerFieldUpdater:原子更新整型字段的值。
    1. static <T> AtomicIntegerFieldUpdater<T> newUpdater(Class<T> tClass, String fieldName):創建一個新的原子整型字段更新器。
    2. int get(T obj):獲取指定對象中字段的當前值。
    3. void set(T obj, int newValue):設置指定對象中字段的值為指定的新值。
    4. int getAndSet(T obj, int newValue):獲取并設置指定對象中字段的值為指定的新值。
  2. AtomicLongFieldUpdater:原子更新長整型字段的值。
    1. static <T> AtomicLongFieldUpdater<T> newUpdater(Class<T> tClass, String fieldName):創建一個新的原子長整型字段更新器。
    2. long get(T obj):獲取指定對象中字段的當前值。
    3. void set(T obj, long newValue):設置指定對象中字段的值為指定的新值。
    4. long getAndSet(T obj, long newValue):獲取并設置指定對象中字段的值為指定的新值。
  3. AtomicReferenceFieldUpdater<T, V>:原子更新引用類型字段的值。
    1. static <T,V> AtomicReferenceFieldUpdater<T,V> newUpdater(Class<T> tClass, Class<V> vClass, String fieldName):創建一個新的原子引用類型字段更新器。
    2. V get(T obj):獲取指定對象中字段的當前值。
    3. void set(T obj, V newValue):設置指定對象中字段的值為指定的新值。
    4. V getAndSet(T obj, V newValue):獲取并設置指定對象中字段的值為指定的新值。

使用屬性更新原子類保障安全性的主要流程 大致分為兩部

  1. 更新的對象的屬性必須是 public volatile修飾符
  2. 因為對象的屬性修改類型原子類都是抽象類,所以每次每次使用都必須使用靜態方法

6.2.案例代碼

    @Test@DisplayName("屬性更新原子類")public void test3() {AtomicIntegerFieldUpdater<Data> updater = AtomicIntegerFieldUpdater.newUpdater(Data.class, "value");Data data = new Data(10);// 獲取并輸出當前值log.error("初始值:{}",updater.get(data));// 嘗試原子性地將值更新為20updater.set(data, 20);log.error("更新后的值:{}",updater.get(data));// 嘗試原子性地獲取并更新值為30int oldValue = updater.getAndSet(data, 30);log.error("原來的值:{}", oldValue);log.error("更新后的值:{}", updater.get(data));}class Data {public volatile int value; // 要更新的字段必須是 volatile 的public Data(int value) {this.value = value;}}

在這里插入圖片描述

這個代碼了如何使用AtomicIntegerFieldUpdater類來原子性地更新Data對象中的整型字段value的值。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/11731.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/11731.shtml
英文地址,請注明出處:http://en.pswp.cn/web/11731.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

StackQueue+泛型簡單理解

&#x1f341; 個人主頁&#xff1a;愛編程的Tom&#x1f4ab; 本篇博文收錄專欄&#xff1a;Java專欄&#x1f449; 目前其它專欄&#xff1a;c系列小游戲 c語言系列--萬物的開始_ &#x1f389; 歡迎 &#x1f44d;點贊?評論?收藏&#x1f496;三連支持一…

ddpm Denoising Diffusion Probabilistic Model 學習筆記

目錄 Stable Diffusion 文章的貢獻抽象出來就兩個 潛空間上做擴散生成 ddpm(Denoising Diffusion Probabilistic Model)學習筆記 算法原理 unet預測噪聲 unet推理過程 重參數化技巧 &#xff08;1&#xff09;利用前一時刻的 xt-1 得到任意時刻的噪聲圖片 xt&#xff…

LeetCode2215找出兩數組的不同

題目描述 給你兩個下標從 0 開始的整數數組 nums1 和 nums2 &#xff0c;請你返回一個長度為 2 的列表 answer &#xff0c;其中&#xff1a;answer[0] 是 nums1 中所有 不 存在于 nums2 中的 不同 整數組成的列表。answer[1] 是 nums2 中所有 不 存在于 nums1 中的 不同 整數組…

Linux poweroff命令教程:如何實現一鍵關機(附實例詳解和注意事項)

Linux poweroff命令介紹 poweroff命令是用來關閉系統的。當你執行這個命令時&#xff0c;它會發送一個信號給系統&#xff0c;告訴系統關閉所有的進程&#xff0c;然后關閉系統。這個命令非常有用&#xff0c;特別是在你需要遠程關閉系統&#xff0c;或者你的系統沒有圖形用戶…

Autosar架構

藍框那種叫component&#xff0c;綠框的叫function cluster。 接口 有三種接口&#xff0c;RTE跟SWC之間鏈接的叫Autosar Interface&#xff0c;RTE跟BSW的Components鏈接是Standardized Interface&#xff0c;RTE跟BSW的services鏈接的是Standardized Autosar Interface。 St…

項目部署到線上proxytable代理失效nginx報404的問題

我的項目是在vue的config文件夾中的index.js中配置了接口地址 &#xff0c;本地跑的時候都能訪問&#xff0c;放到線上就報404&#xff1b; module.exports {dev: {// PathsassetsSubDirectory: static,assetsPublicPath: /,proxyTable: {/xxx: {target: http://xxxxxxxx:xxx…

分享四種CAD圖紙加密方法,嚴防盜圖

在數字化時代&#xff0c;cad圖紙的盜用和非法傳播問題日益突出。對于企業和設計師來說&#xff0c;保護設計成果的安全性和原創性&#xff0c;采取有效的cad加密方法至關重要。本文將分享四種cad加密方法&#xff0c;幫助您嚴防盜圖&#xff0c;保護圖紙安全。 使用cad軟件內…

網絡協議的分類

1.概要 網絡協議可以分為三類&#xff1a; 封裝協議路由協議功能類協議 2.分類說明 OSPF報文直接調用_ IP協議__協議進行封裝&#xff0c;以目的地址_244.0.0.5 __發送到所有的OSPF路由器? 244.0.0.1 所有主機&#xff1b;244.0.0.2 所有路由器&#xff1b;244.0.0.6 指定…

【前端每日一題】day5

JS 實現繼承的幾種方式 在JavaScript中&#xff0c;實現繼承的幾種方式包括原型鏈繼承、構造函數繼承、組合繼承、原型式繼承、寄生式繼承和組合式繼承。 原型鏈繼承&#xff1a; function Parent() {this.name Parent; } Parent.prototype.sayHello function() {console.…

當它還是幼生期的時候,及早離開它!

當我們有豐富的精神生活時&#xff0c;充實的知識吸收儲備時&#xff0c;為自己的每一點進步而欣慰時&#xff0c;我們就不會有失敗的憂慮。也不會有孤單的自憐。 沒有人是弱者&#xff0c;每個人都有自己活著的方式&#xff0c;當你內心強大時&#xff0c;你會尊重每一個“弱者…

Vue+springboot的批量刪除功能

vue前臺 <div style"margin-bottom: 10px"><el-button type"primary" plain click"handleAdd">新增</el-button><el-button click"delBatch" type"danger" plain style"margin-left: 5px"…

Spring Cloud 背后技術詳解

Spring Cloud 是基于 Spring Boot 的一套微服務架構解決方案。它為開發者提供了一系列的工具&#xff0c;用于快速構建分布式系統中的一些常見模式&#xff08;例如配置管理、服務發現、斷路器等&#xff09;。Spring Cloud 利用 Spring Boot 的自動配置和獨立運行能力&#xf…

C語言例題41、八進制轉換為十進制

#include<stdio.h>void main() {int x;printf("請輸入一個8進制整數&#xff1a;");scanf("%o", &x);printf("轉換成十進制后的整數為%d\n", x); }運行結果&#xff1a; 本章C語言經典例題合集&#xff1a;http://t.csdnimg.cn/FK0Qg…

Java基礎(33)Java Web攔截器作用和用法

Java Web攔截器&#xff08;Interceptor&#xff09;是Java Web開發中一個重要的概念&#xff0c;它允許開發者在處理HTTP請求和響應之前或之后執行特定的代碼&#xff0c;從而實現如權限檢查、日志記錄、事務管理等功能。攔截器可以作用于Java EE的Servlet、Spring框架、Strut…

redis試題按知識點歸類(四)

十六、實戰應用 1.如何使用 Redis 存儲用戶會話&#xff1f; 2.Redis 在電子商務平臺中的應用是什么&#xff1f; 3.如何使用 Redis 進行實時數據分析&#xff1f; 十七、面試題綜合 1.描述一次你解決 Redis 性能問題的經歷。 2.你如何理解 Redis 中的“單線程”模型&…

Java入門基礎學習筆記21——Scanner

在程序中接收用戶通過鍵盤輸入的數據&#xff1a; 需求&#xff1a; 請在程序中&#xff0c;提示用戶通過鍵盤輸入自己的姓名、年齡、并能在程序中收到這些信息&#xff0c;怎么解決&#xff1f; Java已經寫好了實現程序&#xff0c;我們調用即可。 API&#xff1a;Applicat…

2024 年中國大學生程序設計競賽全國邀請賽(鄭州)暨第六屆CCPC河南省大學生程序設計競賽 problem K. 樹上問題

//先找一個美麗的樹&#xff0c;然后遍歷樹找節點,分析是否符合條件。 //畫幾個圖&#xff0c;思考下。 #include<bits/stdc.h> using namespace std; #define int long long const int n1e611; int a,b,c[n],d,l,r,k,w,an; vector<int>t[n]; void dfs(int x,int…

MLT剪輯sample

#include <framework/mlt.h> int main(int argc, char **argv) { // 初始化MLT mlt_factory factory mlt_factory_init(NULL); // 加載素材&#xff08;這里假設我們有一個名為"video.mp4"的視頻文件&#xff09; mlt_profile profile mlt_prof…

什么是頁分裂、頁合并?

數據組織方式 在InnoDB存儲引擎中&#xff0c;表數據都是根據主鍵順序組織存放的&#xff0c;這種存儲方式的表稱為索引組織表(index organized table IOT)。 行數據&#xff0c;都是存儲在聚集索引的葉子節點上的。而我們之前也講解過InnoDB的邏輯結構圖&#xff1a; 在I…

61、內蒙古工業大學、內蒙科學技術研究院:CBAM-CNN用于SSVEP - BCI的分類方法[腦機二區還是好發的]

前言&#xff1a; 之前寫過一篇對CBAM模型改進的博客&#xff0c;在CBAM中引入了ECANet結構&#xff0c;對CBAM中的CAM、SAM模塊逐一改進&#xff0c;并提出ECA-CBAM單鏈雙鏈結構&#xff0c;我的這個小的想法已經被一些同學實現了&#xff0c;并進行了有效的驗證&#xff0c;…