Java大師成長計劃之第18天:Java Memory Model與Volatile關鍵字

📢 友情提示:

本文由銀河易創AI(https://ai.eaigx.com)平臺gpt-4o-mini模型輔助創作完成,旨在提供靈感參考與技術分享,文中關鍵數據、代碼與結論建議通過官方渠道驗證。

在Java多線程編程中,線程安全是一個常見且重要的議題。而理解Java內存模型(Java Memory Model, JMM)和volatile關鍵字的作用,是開發線程安全程序的關鍵。Java內存模型描述了多線程環境下共享變量的行為,以及線程之間如何交互和同步。volatile關鍵字則是保證變量可見性的一種簡單而有效的手段。

本篇博客將詳細講解Java內存模型的工作原理、內存模型與變量可見性之間的關系、volatile關鍵字的使用以及它如何影響并發程序的行為。

一. 什么是Java內存模型(JMM)?

1.1 內存模型概述

Java內存模型(Java Memory Model,JMM)是Java虛擬機(JVM)規范的一部分,旨在提供一個統一的、多線程環境下的內存訪問模型。它描述了如何在并發程序中使用共享變量,并定義了線程之間如何進行通信以及這些操作如何影響變量的可見性和順序性。JMM的設計目標是實現以下幾個方面:

  1. 保證程序的安全性:確保多線程環境中對共享變量的訪問和修改是安全的,避免數據的不一致和錯誤狀態。
  2. 提升性能:通過允許JVM和編譯器進行優化,提升多線程程序的執行效率,同時又不影響程序的正確性。
  3. 提高可理解性:為開發者提供清晰的模型,使其能夠更好地理解在并發編程中可能出現的各種行為和問題。

1.2 JMM的核心概念

Java內存模型的設計圍繞著幾個關鍵的概念展開,這些概念是理解JMM如何工作的基礎。

1.2.1 主內存與工作內存

在Java中,內存的管理主要分為兩個層面:

  • 主內存(Main Memory):這是所有共享變量的存儲區域。所有的實例變量和靜態變量都存儲在主內存中。當線程需要訪問共享變量時,必須先從主內存中讀取數據。

  • 工作內存(Working Memory):每個線程都有自己獨立的工作內存,用于存儲該線程的共享變量的副本。線程對共享變量的所有操作都是在自己的工作內存中進行的,線程直接操作工作內存中的數據,而不是直接訪問主內存中的共享變量。

1.2.2 變量的可見性

Java內存模型保證了線程之間的可見性。具體來說,當一個線程對共享變量進行修改時,其他線程必須能夠及時看到這個修改。JMM通過定義一系列的規則,確保操作的可見性。為了實現可見性,JMM要求線程在訪問共享變量時,必須將變量的最新值從主內存讀取到自己的工作內存中,并在修改后將修改的值刷新回主內存。

1.2.3 原子性

原子性是指操作不可分割,多個線程對共享變量的操作要么完全成功,要么完全不執行。JMM保證了一些特定的操作(如讀取和寫入基本類型的變量)是原子的,但對于復合操作(例如自增操作)則不一定具有原子性。在多線程環境中,如果多個線程同時對同一共享變量進行操作,而沒有適當的同步機制,就可能導致數據的不一致性。

1.2.4 有序性

有序性描述了程序中指令執行的順序。JMM允許JVM和編譯器對指令進行重排序,以改善性能,但重排序不能破壞程序的邏輯順序。JMM提供了一些規則來保證在特定條件下,程序的執行順序是可控的,避免因重排序導致的錯誤執行。

1.3 JMM的保證

Java內存模型通過一些基本的規則和約束,確保了在多線程環境中對共享變量的操作是安全的。這些保證主要包括:

  1. 可見性保證:對于共享變量的所有寫操作,必須保證在之后的讀操作中可見。這意味著,一個線程對共享變量的修改必須被及時刷新到主內存中,從而確保其他線程讀取到最新的值。

  2. 原子性保證:對于某些基本類型的操作,JMM確保這些操作的原子性。然而,對于復雜的復合操作,開發者需要使用適當的同步機制(如synchronizedLock等),以確保操作的原子性。

  3. 有序性保證:JMM允許線程在執行時對指令進行重排序,以提升性能,但重排序不能改變程序的邏輯結果。為了保證可見性和有序性,開發者可以使用同步機制來控制線程的執行順序。

1.4 小結

Java內存模型(JMM)為多線程編程提供了一個框架,使得開發者能夠理解和控制線程之間的交互。通過主內存與工作內存的分離、可見性、原子性和有序性等核心概念,JMM確保了在復雜的并發環境中,程序的行為是可預期的。理解這些概念及其背后的原理,能夠幫助開發者更好地設計和實現線程安全的程序,避免常見的并發問題,提升應用程序的性能和穩定性。

二. 變量的可見性與JMM

2.1 可見性問題的出現

在多線程編程中,可見性是一個重要的概念,它指的是一個線程對共享變量所做的修改,能否被其他線程及時看到。當多個線程同時訪問共享變量時,如果沒有適當的同步機制,可能會導致可見性問題。

2.1.1 共享變量的修改

在Java中,線程在執行時會將共享變量的值從主內存加載到自己的工作內存中。此時,線程對該變量的所有操作都是在工作內存中進行的。若線程對共享變量進行了修改,這個修改首先反映在工作內存中,而不是立即寫入主內存。這就可能導致其他線程在訪問這個共享變量時,讀取到的是一個過時的值。例如,考慮以下簡單的代碼片段:

public class VisibilityExample {private static boolean flag = false;public static void main(String[] args) throws InterruptedException {Thread writerThread = new Thread(() -> {try {// 暫停一秒鐘,讓readerThread有機會開始運行Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}flag = true; // 修改共享變量System.out.println("Writer Thread: flag is updated to true");});Thread readerThread = new Thread(() -> {while (!flag) {// 線程持續檢查flag的值}System.out.println("Reader Thread: flag is now true, exiting loop");});writerThread.start();readerThread.start();writerThread.join();readerThread.join();}
}

在這個示例中,writerThread在經過一秒后將flag的值設置為true,而readerThread則不斷檢查flag的值。在沒有適當的同步機制下,readerThread可能會一直讀取到flag的舊值(即false),導致程序進入無限循環。這是因為readerThread讀取的可能是工作內存中緩存的舊值,而不是主內存中的最新值。

2.2 JMM中的可見性保證

Java內存模型為確保多線程環境中的可見性提供了一些保證和機制。JMM定義了一系列規則,確保線程之間對共享變量的修改是可見的。

2.2.1 主內存同步

JMM規定了共享變量的寫操作需要被同步刷新到主內存,而讀取操作需要從主內存加載最新值。當一個線程對共享變量進行修改時,它必須將修改后的值刷新回主內存,其他線程隨后讀取共享變量時就能獲取到最新的值。這種機制保證了多個線程之間的可見性。

2.2.2 使用synchronizedvolatile

為了確保可見性,Java提供了幾種方法來控制對共享變量的訪問:

  1. 使用synchronized關鍵字:當一個線程進入synchronized修飾的方法或代碼塊時,它會先獲取鎖,其他線程在嘗試進入該區域時會被阻塞。synchronized不僅保證了互斥訪問,還確保了共享變量的可見性。當線程釋放鎖時,它會將修改過的變量刷新到主內存中,其他線程在獲取鎖時可以看到最新的值。

    public synchronized void updateFlag() {flag = true; // 線程對flag的修改是可見的
    }
    
  2. 使用volatile關鍵字volatile關鍵字是Java中另一種確保可見性的方式。當一個變量被聲明為volatile時,JMM保證所有線程在訪問該變量時,都會從主內存中讀取最新的值,而不是從工作內存中讀取。這消除了共享變量的可見性問題。

    private volatile boolean flag = false; // 確保flag的可見性public void updateFlag() {flag = true; // 其他線程能夠立即看到這個更新
    }
    

2.3 可見性與性能的權衡

在多線程應用中,可見性和性能之間往往存在一種權衡。雖然使用synchronizedvolatile可以保證變量的可見性,但這通常會引入一定的性能開銷。尤其是在高并發環境下,頻繁的鎖競爭會導致上下文切換,降低程序的整體性能。

2.3.1 鎖的爭用

當使用synchronized修飾塊或方法時,線程在獲取鎖時會發生阻塞。每當一個線程請求鎖時,如果鎖已經被其他線程持有,該線程將被迫等待,直到鎖被釋放。對于高并發的場景,這種競爭可能會導致性能瓶頸。

2.3.2 讀寫鎖的使用

為了解決可見性和性能之間的矛盾,可以使用ReadWriteLockReadWriteLock允許多個線程并發讀取共享變量,但在進行寫操作時會獨占訪問。這樣,當讀操作遠多于寫操作時,可以大幅度提高程序的并發性能。

ReadWriteLock rwLock = new ReentrantReadWriteLock();public void read() {rwLock.readLock().lock();try {// 讀取操作} finally {rwLock.readLock().unlock();}
}public void write() {rwLock.writeLock().lock();try {// 寫入操作} finally {rwLock.writeLock().unlock();}
}

2.4 小結

在多線程編程中,變量的可見性是確保數據一致性的關鍵因素。Java內存模型通過定義主內存與工作內存的交互機制,保證了線程對共享變量的修改能夠被其他線程及時看到。通過使用synchronizedvolatile關鍵字,開發者能夠有效地解決并發環境中的可見性問題。

然而,開發者在選擇同步機制時,需要權衡可見性與性能之間的關系。在高并發的應用場景中,合理使用鎖機制與優化策略,將有助于提高系統的整體性能,確保程序的可靠性和高效性。理解可見性原理及其在JMM中的應用,是編寫高效和安全的多線程程序的基礎。

三.?volatile關鍵字

3.1?volatile的基本概念

volatile是Java中用于修飾變量的一個關鍵字,主要作用是確保變量在多個線程之間的可見性。通過聲明一個變量為volatile,Java內存模型(JMM)確保所有線程對該變量的修改將立刻反映到主內存中,避免每個線程在其本地工作內存中操作一個陳舊的副本。

3.1.1 可見性與原子性

volatile關鍵字提供的是可見性保證,但它并不保證操作的原子性。原子性指的是某個操作要么完全成功,要么完全失敗,不會被中斷。在多線程并發訪問時,如果多個線程同時修改一個volatile變量,volatile不能保證這些操作的原子性,因此需要通過其他手段(如Atomic類或synchronized)來確保原子性。

3.2?volatile的工作原理

volatile的作用是在多線程環境下,確保對變量的讀寫操作直接發生在主內存上,而非線程的工作內存中。具體來說:

  1. 主內存更新:當一個線程修改volatile變量時,它的更新會直接寫入主內存,而不是僅僅保存在該線程的工作內存中。
  2. 工作內存同步:當其他線程訪問這個volatile變量時,它們會直接從主內存中讀取最新的值,而不是從線程的工作內存中讀取緩存的舊值。

這種機制避免了多個線程之間的內存可見性問題。例如,一個線程修改volatile變量后,其他線程能夠立刻看到這個修改,而不必等待線程間的同步操作。

3.3?volatile關鍵字的使用場景

volatile常常被用于處理簡單的共享狀態標志、指示值或者標識符。這些場景中,變量的變化不涉及復雜的計算或依賴,且對可見性的要求非常高。具體使用場景包括:

3.3.1 狀態標志

volatile可以用來作為控制線程執行的標志位。例如,一個線程用來標記是否需要退出,其他線程會檢查該標志位的值。如果標志位為true,則表示線程應該退出。這種狀態標志的修改通常會被多個線程讀取和更新,因此必須使用volatile來確保所有線程都能看到該標志位的最新值。

public class VolatileFlagExample {private volatile boolean flag = false;public void setFlagTrue() {flag = true; // 線程1修改flag的值}public void checkFlag() {while (!flag) {// 線程2持續檢查flag,若flag為false則繼續}System.out.println("Flag is true, thread exits");}
}

在這個例子中,flag被聲明為volatile,因此checkFlag線程會看到setFlagTrue線程對flag變量的修改,避免了線程間的可見性問題。

3.3.2 單例模式(Double-Checked Locking)

volatile在雙重檢查鎖定(Double-Checked Locking)模式中也非常常見。在單例模式中,volatile可以確保對象在創建時被正確初始化,且確保其他線程能看到該對象的最新狀態,避免指令重排序造成的問題。

public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}

在這個單例模式的實現中,instance被聲明為volatile,確保instance的初始化過程不會被指令重排序打亂。volatile確保當一個線程初始化了instance變量后,其他線程能夠立即看到該實例。

3.4?volatile的限制

雖然volatile在確保可見性方面非常有用,但它也有一些明顯的限制。開發者在使用volatile時,必須明確這些限制,否則可能導致程序中的問題。

3.4.1 不保證原子性

volatile只提供了對單一變量的可見性保證,但它并不保證復合操作的原子性。復合操作指的是多步操作,例如count++i = i + 1等。在這些操作中,volatile并沒有保證線程間操作的原子性,這樣多個線程可能會在執行類似i = i + 1這樣的操作時產生競爭條件,從而導致數據不一致。

public class VolatileAtomicityExample {private volatile int count = 0;public void increment() {count++;  // 不是原子操作}
}

在這個例子中,count++是一個非原子操作,它涉及到讀取count的值、增加1、再寫回count。多個線程并發調用increment()時,可能導致count的值不準確。因此,在這種情況下,volatile并不能保證線程安全,開發者應該使用AtomicInteger類或者其他同步機制來保證原子性。

3.4.2 僅限于單一變量

volatile只能保證單個變量的可見性問題,對于多個變量的同步控制,它無法處理。對于涉及多個共享變量的操作,開發者仍然需要使用Locksynchronized來保證原子性和一致性。例如,以下代碼需要保證多個變量的原子性,但volatile無法保證:

public class VolatileMultipleVariables {private volatile int count;private volatile int sum;public void increment() {count++;sum += count;  // 兩個變量操作,無法通過volatile保證同步}
}

在這種情況下,count++sum += count必須一起執行,才能保證數據一致性。然而,volatile無法解決兩個變量之間的協調問題,因此,應該使用Atomic類或synchronized來進行線程同步。

3.5?volatilesynchronized的對比

volatilesynchronized都可以用于多線程編程,但它們解決的問題有所不同:

  • volatile:主要用于保證變量的可見性,它不會保證操作的原子性。如果線程之間僅僅是對某個變量的讀取和寫入,且沒有其他復雜操作,可以考慮使用volatile來確保可見性。

  • synchronized:用于確保對資源的互斥訪問,它不僅保證了可見性,還能確保操作的原子性。當多個線程訪問共享資源并修改其值時,synchronized能夠避免競態條件,確保程序的線程安全。

3.6?volatile與現代并發庫

現代并發編程中的一些高級工具類,通常會在內部利用volatile關鍵字來解決可見性問題。例如,Java中的Atomic類(如AtomicIntegerAtomicLong等)在保證原子性時,內部實現通常會結合使用volatile。這些類提供了更高效、線程安全的方式來處理共享變量的訪問,同時避免了使用synchronized所帶來的性能開銷。

AtomicInteger atomicCount = new AtomicInteger(0);// 線程安全的遞增操作
atomicCount.incrementAndGet();

在這個例子中,AtomicInteger使用了volatile來保證atomicCount的可見性,并通過CAS(比較并交換)來保證原子性。因此,在高并發情況下,AtomicInteger等類提供了比synchronized更加高效的解決方案。

3.7 總結

volatile關鍵字是Java中非常重要的并發工具,它通過保證共享變量的可見性,避免了線程間的內存可見性問題。然而,volatile僅僅適用于簡單的變量操作,不能保證復雜操作的原子性。在涉及多個變量或復雜操作時,開發者應該使用Atomic類或synchronized來確保線程安全。

通過合理使用volatile,可以在高效的并發環境中,避免因緩存問題造成的數據不一致,提高程序的性能和可靠性。但同時,理解volatile的限制,并在適當的場景下選擇合適的并發控制機制,是開發高效并發程序的關鍵。

四.?volatilesychronized的比較

volatile通常用于處理狀態標志位、簡單的共享數據或者信號量等場景,在這些場景中,變量的修改不涉及復雜的操作或者依賴關系。

4.1.2?synchronized的功能

synchronized關鍵字用于保證原子性互斥性。它不僅保證了變量的可見性,還能確保對共享資源的訪問是互斥的。具體來說:

synchronized適用于需要保證數據一致性、線程安全且操作復雜的場景,例如數據庫操作、文件讀寫、集合類操作等。

4.2 適用場景

4.2.1?volatile適用場景

volatile適用于以下場景:

4.2.2?synchronized適用場景

synchronized適用于以下場景:

4.3 性能差異

4.3.1?volatile的性能

volatile相比synchronized具有較低的性能開銷。原因如下:

不過,synchronized的性能問題可以通過一些優化措施來減少,例如使用ReentrantLock等高級鎖機制,或通過細粒度鎖的設計降低鎖競爭。

4.4?volatilesynchronized的對比總結

特性volatilesynchronized
功能主要保證變量的可見性保證原子性、互斥性和可見性
適用場景簡單的狀態標志、共享變量復雜操作的同步控制、資源訪問控制
原子性不保證復合操作的原子性保證對共享變量的操作是原子性的
性能開銷性能較低,不涉及鎖競爭性能較高,涉及鎖的獲取和釋放,會有較大開銷
線程安全性只能保證單個變量的可見性,不能保證線程安全保證代碼塊或方法內的線程安全,防止競態條件
鎖的粒度無鎖機制基于鎖的機制,涉及線程間的鎖競爭
適用范圍適用于簡單的標志位、狀態控制等場景適用于需要保障原子性、互斥性的復雜共享資源操作

  • 在Java的多線程編程中,volatilesynchronized是兩個常用的關鍵字,它們用于處理線程之間的同步和共享變量的訪問。雖然它們都涉及到并發控制,但它們的使用場景、工作原理、優缺點和性能開銷存在顯著差異。理解volatilesynchronized之間的區別,可以幫助開發者在不同的并發編程場景中做出更加高效和合理的選擇。

    4.1 功能差異

    4.1.1?volatile的功能

    volatile主要解決的是可見性問題。當一個變量被聲明為volatile時,JVM保證它在多個線程之間的值是即時可見的。具體來說:

  • 可見性:當一個線程修改了volatile變量的值,其他線程立刻能夠看到這個修改。這是因為volatile變量不會被緩存到線程的工作內存中,而是直接從主內存讀取。
  • 禁止重排序volatile變量的寫操作和讀操作不能被JVM或編譯器重排序。它保證了讀寫操作的順序,避免了指令重排序帶來的潛在問題。
  • 互斥性:當一個線程獲取到synchronized鎖時,其他線程必須等待該線程釋放鎖才能繼續執行。這避免了多個線程同時訪問同一資源的競爭問題。
  • 原子性synchronized確保對共享變量的操作是原子性的,即在一個線程操作某個共享資源時,其他線程不能同時修改該資源。這樣,synchronized能夠有效避免競態條件和數據不一致問題。
  • 可見性synchronized還保證了鎖的釋放和獲取操作時,變量的修改會同步到主內存,從而確保線程間對共享變量的可見性。
  • 標志位或狀態控制:當一個線程用來控制另一個線程的執行狀態時,volatile是一個合適的選擇。例如,線程安全的停止標志位(stopFlag)通常會使用volatile,以確保線程可以及時看到標志位的變化。

    private volatile boolean stopFlag = false;public void stopThread() {stopFlag = true;  // 確保其他線程看到最新的stopFlag
    }
    
  • 簡單的共享變量:當多個線程需要共享一個值,并且該值的操作是簡單的(如狀態變量的讀取和修改),volatile能夠確保變量的可見性。

  • 單例模式volatile可用于單例模式中的“雙重檢查鎖定”(Double-Checked Locking)方式,確保在多線程環境中安全地創建實例。

    private static volatile Singleton instance;public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;
    }
    
  • 復雜操作的線程安全:對于多個線程需要同時訪問并修改某些共享資源的情況,synchronized確保操作的原子性和互斥性,避免了并發操作導致的數據不一致問題。

  • 資源訪問控制:在高并發環境下,當多個線程需要對同一資源進行獨占訪問時(例如文件、數據庫等),synchronized確保只有一個線程能夠在同一時間內訪問該資源。

  • 多步驟操作:當操作涉及多個步驟,且這些步驟必須作為一個原子操作執行時(例如讀、修改、寫等操作),synchronized能夠保證這些操作不會被其他線程中斷,避免了競態條件。

    public synchronized void increment() {counter++;  // 保證對counter的操作是原子性的
    }
    
  • 無鎖機制volatile沒有鎖的機制,因此不需要進行上下文切換或競爭鎖,避免了由于鎖帶來的性能損耗。
  • 簡單的內存屏障volatile通過內存屏障(memory barrier)確保變量的可見性,開銷相對較小。
  • 鎖的競爭:當多個線程競爭同一鎖時,線程會進行上下文切換,導致性能下降。尤其是在高并發環境下,鎖競爭會顯著影響系統性能。
  • 內存同步synchronized不僅僅保證了原子性,還確保了線程間的可見性,每次進入同步代碼塊時,都會強制刷新共享變量到主內存,從而帶來額外的性能開銷。
  • 鎖的粒度synchronized的性能還與鎖的粒度有關。粗粒度鎖(鎖范圍大)可能導致較大的性能損失,而細粒度鎖(鎖范圍小)雖然能提高并發性,但也會增加鎖的管理開銷。

4.5 小結

volatilesynchronized都在Java多線程編程中扮演著重要角色,但它們的使用場景、功能和性能特性有顯著差異。

volatile?適用于需要保證變量可見性且操作簡單的場景,它能有效減少同步的性能開銷,但不保證原子性,適用于標志位、單例模式等。 synchronized?適用于需要保證線程安全和原子性的復雜操作,如多個線程修改共享數據的情況,它通過鎖機制提供互斥性和可見性,但性能開銷較大。

開發者應根據具體的場景選擇合適的并發控制方式,在保證線程安全的同時,盡量降低性能損耗。理解volatilesynchronized的不同特點,可以幫助開發者在多線程編程中作出更加高效的決策。

    五. 總結

    理解Java內存模型(JMM)和volatile關鍵字的使用,對于編寫線程安全且高效的并發程序至關重要。JMM提供了多線程環境下的內存可見性、原子性和有序性的基礎規范,而volatile關鍵字則是實現變量可見性的高效工具。雖然volatile能保證可見性,但它不能保證原子性,因此需要與其他機制(如Atomic類或synchronized)結合使用。

    通過正確使用JMM和volatile,我們可以避免并發編程中常見的錯誤,提高程序的可靠性和性能。掌握這些概念,將使你在多線程編程中游刃有余。

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

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

    相關文章

    js前端分片傳輸大文件+mongoose后端解析

    最近一直在完善mongoose做webserver的項目,其中程序升級要通過前端傳輸升級包到服務器。 因為第一次寫前端代碼,分片傳輸的邏輯,網上一堆,大同小異,而且版本啊,API不一致的問題,導致頭疼的很。后…

    MiniMind:3塊錢成本 + 2小時!訓練自己的0.02B的大模型。minimind源碼解讀、MOE架構

    大家好,我是此林。 目錄 1. 前言 2. minimind模型源碼解讀 1. MiniMind Config部分 1.1. 基礎參數 1.2. MOE配置 2. MiniMind Model 部分 2.1. MiniMindForCausalLM: 用于語言建模任務 2.2. 主干模型 MiniMindModel 2.3. MiniMindBlock: 模型的基本構建塊…

    引言:Client Hello 為何是 HTTPS 安全的核心?

    當用戶在瀏覽器中輸入 https:// 時,看似簡單的操作背后,隱藏著一場加密通信的“暗戰”。Client Hello 作為 TLS 握手的首個消息,不僅決定了后續通信的加密強度,還可能成為攻擊者的突破口。據統計,超過 35% 的網站因 TL…

    Dockerfile 完全指南:從入門到最佳實踐

    Dockerfile 完全指南:從入門到最佳實踐 1. Dockerfile 簡介與作用 Dockerfile 是一個文本文件,包含了一系列用于構建 Docker 鏡像的指令。它允許開發者通過簡單的指令定義鏡像的構建過程,實現自動化、可重復的鏡像構建。 主要作用&#xf…

    Python httpx庫終極指南

    一、發展歷程與技術定位 1.1 歷史演進 起源:httpx 由 Encode 團隊開發,于 2019 年首次發布,目標是提供一個現代化的 HTTP 客戶端,支持同步和異步操作,并兼容 HTTP/1.1 和 HTTP/2。背景: requests 庫雖然功…

    app加固

    1、什么是加固? 我們之前講的逆向,大多數都是用加密算法去加密一些明文字符串,然后把得到的結果用 Base64、Hex等進行編碼后提交。加固其實也一樣,只不過他通常加密的是 dex文件而已。但是 dex 文件加密以后,安卓系統是沒法直接運行的。所以加固的核心&…

    Win全兼容!五五 Excel Word 轉 PDF 工具解決多場景轉換難題

    各位辦公小能手們!今天給你們介紹一款超牛的工具——五五Excel Word批量轉PDF工具V5.5版。這玩意兒專注搞批量格式轉換,能把Excel(.xls/.xlsx)和Word(.doc/.docx)文檔唰唰地變成PDF格式。 先說說它的核心功…

    springCloud/Alibaba常用中間件之Nacos服務注冊與發現

    文章目錄 SpringCloud Alibaba:依賴版本補充六、Nacos:服務注冊與發現1、下載安裝Nacos2、服務注冊1. 導入依賴(這里以服務提供者為例)2. 修改配置文件和主啟動類3. 創建業務類4. 測試 3.服務映射1. 導入依賴2. 修改配置文件和主啟動類3. 創建業務類和RestTemplate配置類用來提…

    uniapp中score-view中的文字無法換行問題。

    項目場景: 今天遇到一個很惡心的問題,uniapp中的文字突然無法換行了。得..就介樣 原因分析: 提示:經過一fan研究后發現 scroll-view為了能夠橫向滾動設置了white-space: nowrap; 強制不換行 解決起來最先想到的是,父…

    【STM32 學習筆記】I2C通信協議

    注:通信協議的設計背景 3:00~10:13 I2C 通訊協議(Inter-Integrated Circuit)是由Phiilps公司開發的,由于它引腳少,硬件實現簡單,可擴展性強, 不需要USART、CAN等通訊協議的外部收發設備,現在被廣…

    【網絡原理】數據鏈路層

    目錄 一. 以太網 二. 以太網數據幀 三. MAC地址 四. MTU 五. ARP協議 六. DNS 一. 以太網 以太網是一種基于有線或無線介質的計算機網絡技術,定義了物理層和數據鏈路層的協議,用于在局域網中傳輸數據幀。 二. 以太網數據幀 1)目標地址 …

    控制臺打印帶格式內容

    1. 場景 很多軟件會在控制臺打印帶顏色和格式的文字,需要使用轉義符實現這個功能。 2. 詳細說明 2.1.轉義符說明 樣式開始:\033[參數1;參數2;參數3m 可以多個參數疊加,若同一類型的參數(如字體顏色)設置了多個&…

    [6-2] 定時器定時中斷定時器外部時鐘 江協科技學習筆記(41個知識點)

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 V 30 31 32 33 34 35 36 37 38 39 40 41

    數據庫的脫敏策略

    數據庫的脫敏策略:就是屏蔽敏感的數據 脫敏策略三要求: (1)表對象 (2)生效條件(脫敏列、脫敏函數) (3)二元組 常見的脫敏策略規則: 替換、重排、…

    Python序列化的學習筆記

    1. Npy&Numpy O4-mini-Cursor:如果.npy文件里包含了「Python對象」而非純數值數組時,就必須在加載時加上allow_pickleTrue。

    [思維模式-27]:《本質思考力》-7- 逆向思考的原理與應用

    目錄 一、什么是逆向思考 1.1、逆向思考的六大核心思維模式 1.2、逆向思考的四大實踐方法 1. 假設倒置法 2. 缺陷重構法 3. 用戶反推法 4. 規則解構法 1.3、逆向思考的經典案例庫 1. 商業創新:從“賣產品”到“賣服務” 2. 用戶體驗:從“功能滿…

    在python中,為什么要引入事件循環這個概念?

    在Python中,事件循環(Event Loop)是異步編程的核心機制,它的引入解決了傳統同步編程模型在高并發場景下的效率瓶頸問題。以下從技術演進、性能優化和編程范式三個角度,探討這一概念的必要性及其價值。 一、同步模型的局…

    Taccel:一個高性能的GPU加速視觸覺機器人模擬平臺

    觸覺感知對于實現人類水平的機器人操作能力至關重要。而視覺觸覺傳感器(VBTS)作為一種有前景的解決方案,通過相機捕捉彈性凝膠墊的形變模式來感知接觸的方式,為視觸覺機器人提供了高空間分辨率和成本效益。然而,這些傳…

    oracle 會話管理

    會話管理 1:查看當前所有用戶的會話(SESSION): SELECT * FROM V S E S S I O N W H E R E U S E R N A M E I S N O T N U L L O R D E R B Y L O G O N T I M E , S I D ; 其中 O r a c l e 內部進程的 U S E R N A M E 為空 2 :查看當前…

    Python開發后端InfluxDB數據庫測試接口

    1、使用PyCharm創建一個Python項目wzClear 2、新建package包wzInfluxdb和wzConfig包,如上圖所示,新建一個DB.json配置文件并添加influxdb配置信息,DB.json為統一配置文件 {"influxdbV1": {"url": "http://192.168.0…