JAVA 鎖

樂觀鎖

樂觀鎖是一種樂觀思想,即認為讀多寫少,遇到并發寫的可能性低,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,采取在寫時先讀出當前版本號,然后加鎖操作(比較跟上一次的版本號,如果一樣則更新),如果失敗則要重復讀-比較-寫的操作。

java 中的樂觀鎖基本都是通過 CAS 操作實現的,CAS 是一種更新的原子操作,比較當前值跟傳入值是否一樣,一樣則更新,否則失敗。

悲觀鎖

悲觀鎖是就是悲觀思想,即認為寫多,遇到并發寫的可能性高,每次去拿數據的時候都認為別人會修改,所以每次在讀寫數據的時候都會上鎖,這樣別人想讀寫這個數據就會 block 直到拿到鎖。

java中的悲觀鎖就是Synchronized,AQS框架下的鎖則是先嘗試cas樂觀鎖去獲取鎖,獲取不到,才會轉換為悲觀鎖,如 RetreenLock。

自旋鎖

自旋鎖原理非常簡單,如果持有鎖的線程能在很短時間內釋放鎖資源,那么那些等待競爭鎖的線程就不需要做內核態和用戶態之間的切換進入阻塞掛起狀態,它們只需要等一等(自旋),等持有鎖的線程釋放鎖后即可立即獲取鎖,這樣就避免用戶線程和內核的切換的消耗。

線程自旋是需要消耗 cup 的,說白了就是讓 cup 在做無用功,如果一直獲取不到鎖,那線程也不能一直占用 cup 自旋做無用功,所以需要設定一個自旋等待的最大時間。

如果持有鎖的線程執行的時間超過自旋等待的最大時間扔沒有釋放鎖,就會導致其它爭用鎖的線程在最大等待時間內還是獲取不到鎖,這時爭用線程會停止自旋進入阻塞狀態。

自旋鎖的優缺點

自旋鎖盡可能的減少線程的阻塞,這對于鎖的競爭不激烈,且占用鎖時間非常短的代碼塊來說性能能大幅度的提升,因為自旋的消耗會小于線程阻塞掛起再喚醒的操作的消耗,這些操作會導致線程發生兩次上下文切換!

但是如果鎖的競爭激烈,或者持有鎖的線程需要長時間占用鎖執行同步塊,這時候就不適合使用自旋鎖了,因為自旋鎖在獲取鎖前一直都是占用 cpu 做無用功,占著 XX 不 XX,同時有大量線程在競爭一個鎖,會導致獲取鎖的時間很長,線程自旋的消耗大于線程阻塞掛起操作的消耗,其它需要 cup 的線程又不能獲取到 cpu,造成 cpu 的浪費。所以這種情況下我們要關閉自旋鎖;

自旋鎖時間閾值(1.6 引入了適應性自旋鎖)

自旋鎖的目的是為了占著 CPU 的資源不釋放,等到獲取到鎖立即進行處理。但是如何去選擇自旋的執行時間呢?如果自旋執行時間太長,會有大量的線程處于自旋狀態占用 CPU 資源,進而會影響整體系統的性能。因此自旋的周期選的額外重要!

JVM 對于自旋周期的選擇,jdk1.5 這個限度是一定的寫死的,在 1.6 引入了適應性自旋鎖,適應性自旋鎖意味著自旋的時間不在是固定的了,而是由前一次在同一個鎖上的自旋時間以及鎖的擁有者的狀態來決定,基本認為一個線程上下文切換的時間是最佳的一個時間,同時 JVM 還針對當前 CPU 的負荷情況做了較多的優化,如果平均負載小于 CPUs 則一直自旋,如果有超過(CPUs/2)個線程正在自旋,則后來線程直接阻塞,如果正在自旋的線程發現 Owner 發生了變化則延遲自旋時間(自旋計數)或進入阻塞,如果 CPU 處于節電模式則停止自旋,自旋時間的最壞情況是 CPU的存儲延遲(CPU A 存儲了一個數據,到 CPU B 得知這個數據直接的時間差),自旋時會適當放棄線程優先級之間的差異。

自旋鎖的開啟

JDK1.6 中-XX:+UseSpinning 開啟;

-XX:PreBlockSpin=10 為自旋次數;

JDK1.7 后,去掉此參數,由 jvm 控制;

Synchronized 同步鎖

synchronized 它可以把任意一個非 NULL 的對象當作鎖。他屬于獨占式的悲觀鎖,同時屬于可重入鎖。

Synchronized 作用范圍

  1. 作用于方法時,鎖住的是對象的實例(this);

  2. 當作用于靜態方法時,鎖住的是Class實例,又因為Class的相關數據存儲在永久帶PermGen(jdk1.8 則是 metaspace),永久帶是全局共享的,因此靜態方法鎖相當于類的一個全局鎖,會鎖所有調用該方法的線程;

  3. synchronized 作用于一個對象實例時,鎖住的是所有以該對象為鎖的代碼塊。它有多個隊列,當多個線程一起訪問某個對象監視器的時候,對象監視器會將這些線程存儲在不同的容器中。

Synchronized 核心組件

  1. Wait Set:哪些調用 wait 方法被阻塞的線程被放置在這里;
  2. Contention List:競爭隊列,所有請求鎖的線程首先被放在這個競爭隊列中;
  3. Entry List:Contention List 中那些有資格成為候選資源的線程被移動到 Entry List 中;
  4. OnDeck:任意時刻,最多只有一個線程正在競爭鎖資源,該線程被成為 OnDeck;
  5. Owner:當前已經獲取到所資源的線程被稱為 Owner;
  6. !Owner:當前釋放鎖的線程。

image-20231208201607751

Synchronized 實現

  1. JVM 每次從隊列的尾部取出一個數據用于鎖競爭候選者(OnDeck),但是并發情況下,ContentionList 會被大量的并發線程進行 CAS 訪問,為了降低對尾部元素的競爭,JVM 會將一部分線程移動到 EntryList 中作為候選競爭線程。

  2. Owner 線程會在 unlock 時,將 ContentionList 中的部分線程遷移到 EntryList 中,并指定EntryList 中的某個線程為 OnDeck 線程(一般是最先進去的那個線程)。

  3. Owner 線程并不直接把鎖傳遞給 OnDeck 線程,而是把鎖競爭的權利交給 OnDeck,OnDeck 需要重新競爭鎖。這樣雖然犧牲了一些公平性,但是能極大的提升系統的吞吐量,在JVM 中,也把這種選擇行為稱之為“競爭切換”。

  4. OnDeck 線程獲取到鎖資源后會變為 Owner 線程,而沒有得到鎖資源的仍然停留在 EntryList中。如果 Owner 線程被 wait 方法阻塞,則轉移到 WaitSet 隊列中,直到某個時刻通過 notify或者 notifyAll 喚醒,會重新進去 EntryList 中。

  5. 處于 ContentionList、EntryList、WaitSet 中的線程都處于阻塞狀態,該阻塞是由操作系統來完成的(Linux 內核下采用 pthread_mutex_lock 內核函數實現的)。

  6. Synchronized 是非公平鎖。 Synchronized 在線程進入 ContentionList 時,等待的線程會先嘗試自旋獲取鎖,如果獲取不到就進入 ContentionList,這明顯對于已經進入隊列的線程是不公平的,還有一個不公平的事情就是自旋獲取鎖的線程還可能直接搶占 OnDeck 線程的鎖資源。

  7. 每個對象都有個 monitor 對象,加鎖就是在競爭 monitor 對象,代碼塊加鎖是在前后分別加上 monitorenter 和 monitorexit 指令來實現的,方法加鎖是通過一個標記位來判斷的

  8. synchronized 是一個重量級操作,需要調用操作系統相關接口,性能是低效的,有可能給線程加鎖消耗的時間比有用操作消耗的時間更多。

  9. Java1.6,synchronized 進行了很多的優化,有適應自旋、鎖消除、鎖粗化、輕量級鎖及偏向鎖等,效率有了本質上的提高。在之后推出的 Java1.7 與 1.8 中,均對該關鍵字的實現機理做了優化。引入了偏向鎖和輕量級鎖。都是在對象頭中有標記位,不需要經過操作系統加鎖。

  10. 鎖可以從偏向鎖升級到輕量級鎖,再升級到重量級鎖。這種升級過程叫做鎖膨脹;

  11. JDK 1.6 中默認是開啟偏向鎖和輕量級鎖,可以通過-XX:-UseBiasedLocking 來禁用偏向鎖。

ReentrantLock

ReentantLock 繼承接口 Lock 并實現了接口中定義的方法,他是一種可重入鎖,除了能完成 synchronized 所能完成的所有工作外,還提供了諸如可響應中斷鎖、可輪詢鎖請求、定時鎖等避免多線程死鎖的方法。

Lock 接口的主要方法

  1. void lock(): 執行此方法時, 如果鎖處于空閑狀態, 當前線程將獲取到鎖. 相反, 如果鎖已經被其他線程持有, 將禁用當前線程, 直到當前線程獲取到鎖.

  2. boolean tryLock():如果鎖可用, 則獲取鎖, 并立即返回 true, 否則返回 false. 該方法和lock()的區別在于, tryLock()只是"試圖"獲取鎖, 如果鎖不可用, 不會導致當前線程被禁用, 當前線程仍然繼續往下執行代碼. 而 lock()方法則是一定要獲取到鎖, 如果鎖不可用, 就一直等待, 在未獲得鎖之前,當前線程并不繼續向下執行.

  3. void unlock():執行此方法時, 當前線程將釋放持有的鎖. 鎖只能由持有者釋放, 如果線程并不持有鎖, 卻執行該方法, 可能導致異常的發生.

  4. Condition newCondition():條件對象,獲取等待通知組件。該組件和當前的鎖綁定,當前線程只有獲取了鎖,才能調用該組件的 await()方法,而調用后,當前線程將縮放鎖。

  5. getHoldCount() :查詢當前線程保持此鎖的次數,也就是執行此線程執行 lock 方法的次數。

  6. getQueueLength():返回正等待獲取此鎖的線程估計數,比如啟動 10 個線程,1 個線程獲得鎖,此時返回的是 9

  7. getWaitQueueLength:(Condition condition)返回等待與此鎖相關的給定條件的線程估計數。比如 10 個線程,用同一個 condition 對象,并且此時這 10 個線程都執行了condition 對象的 await 方法,那么此時執行此方法返回 10

  8. hasWaiters(Condition condition):查詢是否有線程等待與此鎖有關的給定條件(condition),對于指定 contidion 對象,有多少線程執行了 condition.await 方法

  9. hasQueuedThread(Thread thread):查詢給定線程是否等待獲取此鎖

  10. hasQueuedThreads():是否有線程等待此鎖

  11. isFair():該鎖是否公平鎖

  12. isHeldByCurrentThread(): 當前線程是否保持鎖鎖定,線程的執行 lock 方法的前后分別是 false 和 true

  13. isLock():此鎖是否有任意線程占用

  14. lockInterruptibly():如果當前線程未被中斷,獲取鎖

  15. tryLock():嘗試獲得鎖,僅在調用時鎖未被線程占用,獲得鎖

  16. tryLock(long timeout TimeUnit unit):如果鎖在給定等待時間內沒有被另一個線程保持,則獲取該鎖。

非公平鎖

JVM 按隨機、就近原則分配鎖的機制則稱為不公平鎖,ReentrantLock 在構造函數中提供了是否公平鎖的初始化方式,默認為非公平鎖。非公平鎖實際執行的效率要遠遠超出公平鎖,除非程序有特殊需要,否則最常用非公平鎖的分配機制。

公平鎖

公平鎖指的是鎖的分配機制是公平的,通常先對鎖提出獲取請求的線程會先被分配到鎖,ReentrantLock 在構造函數中提供了是否公平鎖的初始化方式來定義公平鎖。

ReentrantLock synchronized

  1. ReentrantLock 通過方法 lock()與 unlock()來進行加鎖與解鎖操作,與 synchronized 會被 JVM 自動解鎖機制不同,ReentrantLock 加鎖后需要手動進行解鎖。為了避免程序出現異常而無法正常解鎖的情況,使用 ReentrantLock 必須在 finally 控制塊中進行解鎖操作。

  2. ReentrantLock 相比 synchronized 的優勢是可中斷、公平鎖、多個鎖。這種情況下需要使用 ReentrantLock。

ReentrantLock 實現

public class MyService {private Lock lock = new ReentrantLock();//Lock lock=new ReentrantLock(true);//公平鎖//Lock lock=new ReentrantLock(false);//非公平鎖private Condition condition = lock.newCondition();//創建 Conditionpublic void testMethod() {try {lock.lock();//lock 加鎖//1:wait 方法等待://System.out.println("開始 wait");condition.await();//通過創建 Condition 對象來使線程 wait,必須先執行 lock.lock 方法獲得鎖//:2:signal 方法喚醒condition.signal();//condition 對象的 signal 方法可以喚醒 wait 線程for (int i = 0; i < 5; i++) {System.out.println("ThreadName=" + Thread.currentThread().getName() + (" " + (i + 1)));}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}

Condition 類和 Object 類鎖方法區別區別

  1. Condition 類的 awiat 方法和 Object 類的 wait 方法等效
  2. Condition 類的 signal 方法和 Object 類的 notify 方法等效
  3. Condition 類的 signalAll 方法和 Object 類的 notifyAll 方法等效
  4. ReentrantLock 類可以喚醒指定條件的線程,而 object 的喚醒是隨機的

tryLock lock lockInterruptibly 的區別

  1. tryLock 能獲得鎖就返回 true,不能就立即返回 false,tryLock(long timeout,TimeUnit unit),可以增加時間限制,如果超過該時間段還沒獲得鎖,返回 false

  2. lock 能獲得鎖就返回 true,不能的話一直等待獲得鎖

  3. lock 和 lockInterruptibly,如果兩個線程分別執行這兩個方法,但此時中斷這兩個線程,lock 不會拋出異常,而 lockInterruptibly 會拋出異常。

Semaphore 信號量

Semaphore 是一種基于計數的信號量。它可以設定一個閾值,基于此,多個線程競爭獲取許可信號,做完自己的申請后歸還,超過閾值后,線程申請許可信號將會被阻塞。Semaphore 可以用來構建一些對象池,資源池之類的,比如數據庫連接池

實現互斥鎖(計數器為 1)

我們也可以創建計數為 1 的 Semaphore,將其作為一種類似互斥鎖的機制,這也叫二元信號量,表示兩種互斥狀態。

代碼實現

它的用法如下:

// 創建一個計數閾值為 5 的信號量對象
// 只能 5 個線程同時訪問
Semaphore semp = new Semaphore(5);
try { // 申請許可semp.acquire();try {// 業務邏輯} catch (Exception e) {} finally {// 釋放許可semp.release();}
} catch (InterruptedException e) {}

Semaphore ReentrantLock

Semaphore 基本能完成 ReentrantLock 的所有工作,使用方法也與之類似,通過 acquire()與release()方法來獲得和釋放臨界資源。經實測,Semaphone.acquire()方法默認為可響應中斷鎖,與 ReentrantLock.lockInterruptibly()作用效果一致,也就是說在等待臨界資源的過程中可以被Thread.interrupt()方法中斷。

此外,Semaphore 也實現了可輪詢的鎖請求與定時鎖的功能,除了方法名 tryAcquire 與 tryLock不同,其使用方法與 ReentrantLock 幾乎一致。Semaphore 也提供了公平與非公平鎖的機制,也可在構造函數中進行設定。

Semaphore 的鎖釋放操作也由手動進行,因此與 ReentrantLock 一樣,為避免線程因拋出異常而無法正常釋放鎖的情況發生,釋放鎖的操作也必須在 finally 代碼塊中完成。

AtomicInteger

首先說明,此處 AtomicInteger ,一個提供原子操作的 Integer 的類,常見的還有AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference 等,他們的實現原理相同,區別在與運算對象類型的不同。令人興奮地,還可以通過 AtomicReference將一個對象的所有操作轉化成原子操作。

我們知道,在多線程程序中,諸如++i 或 i++等運算不具有原子性,是不安全的線程操作之一。通常我們會使用 synchronized 將該操作變成一個原子操作,但 JVM 為此類操作特意提供了一些同步類,使得使用更方便,且使程序運行效率變得更高。通過相關資料顯示,通常AtomicInteger的性能是 ReentantLock 的好幾倍。

可重入鎖(遞歸鎖)

本文里面講的是廣義上的可重入鎖,而不是單指 JAVA 下的 ReentrantLock。可重入鎖,也叫做遞歸鎖,指的是同一線程 外層函數獲得鎖之后 ,內層遞歸函數仍然有獲取該鎖的代碼,但不受影響。在 JAVA 環境下 ReentrantLock 和 synchronized 都是 可重入鎖。

公平鎖與非公平鎖

公平鎖(Fair)

加鎖前檢查是否有排隊等待的線程,優先排隊等待的線程,先來先得

非公平鎖(Nonfair)

加鎖時不考慮排隊等待問題,直接嘗試獲取鎖,獲取不到自動到隊尾等待

  1. 非公平鎖性能比公平鎖高 5~10 倍,因為公平鎖需要在多核的情況下維護一個隊列
  2. Java 中的 synchronized 是非公平鎖,ReentrantLock 默認的 lock()方法采用的是非公平鎖。
ReadWriteLock 讀寫鎖

為了提高性能,Java 提供了讀寫鎖,在讀的地方使用讀鎖,在寫的地方使用寫鎖,靈活控制,如果沒有寫鎖的情況下,讀是無阻塞的,在一定程度上提高了程序的執行效率。讀寫鎖分為讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,這是由 jvm 自己控制的,你只要上好相應的鎖即可。

讀鎖

如果你的代碼只讀數據,可以很多人同時讀,但不能同時寫,那就上讀鎖

寫鎖

如果你的代碼修改數據,只能有一個人在寫,且不能同時讀取,那就上寫鎖。總之,讀的時候上讀鎖,寫的時候上寫鎖!

Java 中讀寫鎖有個接口 java.util.concurrent.locks.ReadWriteLock ,也有具體的實現ReentrantReadWriteLock。

共享鎖和獨占鎖

java 并發包提供的加鎖模式分為獨占鎖和共享鎖。

獨占鎖

獨占鎖模式下,每次只能有一個線程能持有鎖,ReentrantLock 就是以獨占方式實現的互斥鎖。獨占鎖是一種悲觀保守的加鎖策略,它避免了讀/讀沖突,如果某個只讀線程獲取鎖,則其他讀線程都只能等待,這種情況下就限制了不必要的并發性,因為讀操作并不會影響數據的一致性。

共享鎖

共享鎖則允許多個線程同時獲取鎖,并發訪問 共享資源,如:ReadWriteLock。共享鎖則是一種樂觀鎖,它放寬了加鎖策略,允許多個執行讀操作的線程同時訪問共享資源。

  1. AQS 的內部類 Node 定義了兩個常量 SHARED 和 EXCLUSIVE,他們分別標識 AQS 隊列中等待線程的鎖獲取模式。

  2. java 的并發包中提供了 ReadWriteLock,讀-寫鎖。它允許一個資源可以被多個讀操作訪問,或者被一個 寫操作訪問,但兩者不能同時進行。

重量級鎖(Mutex Lock)

Synchronized 是通過對象內部的一個叫做監視器鎖(monitor)來實現的。但是監視器鎖本質又是依賴于底層的操作系統的 Mutex Lock 來實現的。而操作系統實現線程之間的切換這就需要從用戶態轉換到核心態,這個成本非常高,狀態之間的轉換需要相對比較長的時間,這就是為什么Synchronized 效率低的原因。因此,這種依賴于操作系統 Mutex Lock 所實現的鎖我們稱之為“重量級鎖”。JDK 中對 Synchronized 做的種種優化,其核心都是為了減少這種重量級鎖的使用。

JDK1.6 以后,為了減少獲得鎖和釋放鎖所帶來的性能消耗,提高性能,引入了“輕量級鎖”和“偏向鎖”。

輕量級鎖

鎖的狀態總共有四種:無鎖狀態、偏向鎖、輕量級鎖和重量級鎖。

鎖升級

隨著鎖的競爭,鎖可以從偏向鎖升級到輕量級鎖,再升級的重量級鎖(但是鎖的升級是單向的,也就是說只能從低到高升級,不會出現鎖的降級)。

“輕量級”是相對于使用操作系統互斥量來實現的傳統鎖而言的。但是,首先需要強調一點的是,輕量級鎖并不是用來代替重量級鎖的,它的本意是在沒有多線程競爭的前提下,減少傳統的重量級鎖使用產生的性能消耗。在解釋輕量級鎖的執行過程之前,先明白一點,輕量級鎖所適應的場景是線程交替執行同步塊的情況,如果存在同一時間訪問同一鎖的情況,就會導致輕量級鎖膨脹為重量級鎖。

偏向鎖

Hotspot 的作者經過以往的研究發現大多數情況下鎖不僅不存在多線程競爭,而且總是由同一線程多次獲得。偏向鎖的目的是在某個線程獲得鎖之后,消除這個線程鎖重入(CAS)的開銷,看起來讓這個線程得到了偏護。引入偏向鎖是為了在無多線程競爭的情況下盡量減少不必要的輕量級鎖執行路徑,因為輕量級鎖的獲取及釋放依賴多次 CAS 原子指令,而偏向鎖只需要在置換ThreadID 的時候依賴一次 CAS 原子指令(由于一旦出現多線程競爭的情況就必須撤銷偏向鎖,所以偏向鎖的撤銷操作的性能損耗必須小于節省下來的 CAS 原子指令的性能消耗)。上面說過,輕量級鎖是為了在線程交替執行同步塊時提高性能,而偏向鎖則是在只有一個線程執行同步塊時進

一步提高性能。

分段鎖

分段鎖也并非一種實際的鎖,而是一種思想 ConcurrentHashMap 是學習分段鎖的最好實踐

鎖優化

減少鎖持有時間

只用在有線程安全要求的程序上加鎖

減小鎖粒度

將大對象(這個對象可能會被很多線程訪問),拆成小對象,大大增加并行度,降低鎖競爭。降低了鎖的競爭,偏向鎖,輕量級鎖成功率才會提高。最最典型的減小鎖粒度的案例就是ConcurrentHashMap。

鎖分離

最常見的鎖分離就是讀寫鎖 ReadWriteLock,根據功能進行分離成讀鎖和寫鎖,這樣讀讀不互斥,讀寫互斥,寫寫互斥,即保證了線程安全,又提高了性能,具體也請查看[高并發 Java 五] JDK 并發包 1。讀寫分離思想可以延伸,只要操作互不影響,鎖就可以分離。比如LinkedBlockingQueue 從頭部取出,從尾部放數據

鎖粗化

通常情況下,為了保證多線程間的有效并發,會要求每個線程持有鎖的時間盡量短,即在使用完公共資源后,應該立即釋放鎖。但是,凡事都有一個度,如果對同一個鎖不停的進行請求、同步和釋放,其本身也會消耗系統寶貴的資源,反而不利于性能的優化 。

鎖消除

鎖消除是在編譯器級別的事情。在即時編譯器時,如果發現不可能被共享的對象,則可以消除這些對象的鎖操作,多數是因為程序員編碼不規范引起。

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

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

相關文章

Sam Altman當選“TIME時代周刊”2023年度最佳CEO!還有梅西、Taylor Swift當選...

TIME時代周刊昨日在官網公布了2023年最佳CEO—— Sam Altman當選! 此外&#xff0c;Taylor Swift當選年度最佳人物&#xff0c;梅西當選年度最佳運動員。 Sam Altman的當選可謂是實至名歸&#xff01;沒有誰能比火爆全球的ChatGPT背后&#xff0c;OpenAI的CEO更“成功”了。 …

ssh安裝及問題解決

ssh安裝及遇到的問題 ssh分為客戶端 openssh-client 和服務器 openssh-server&#xff0c;可以利用以下命令確認是否安裝&#xff1a; dpkg -l | grep ssh我用ubantu安裝的&#xff0c;所以默認安裝了客戶端 安裝客戶端和服務器端的命令分別為&#xff1a; sudo apt-get ins…

金融量化交易:使用Python實現遺傳算法

大家好&#xff0c;遺傳算法是一種受自然選擇過程啟發的進化算法&#xff0c;用于尋找優化和搜索問題的近似解決方案。本文將使用Python來實現一個用于優化簡單交易策略的遺傳算法。 1.遺傳算法簡介 遺傳算法是一類基于自然選擇和遺傳學原理的優化算法&#xff0c;其特別適用…

MySQL 教程 2.1

MySQL 插入數據 MySQL 表中使用 INSERT INTO 語句來插入數據。 你可以通過 mysql> 命令提示窗口中向數據表中插入數據&#xff0c;或者通過PHP腳本來插入數據。 語法 以下為向MySQL數據表插入數據通用的 INSERT INTO SQL語法&#xff1a; INSERT INTO table_name (colu…

使用Pytorch實現Grad-CAM并繪制熱力圖

這篇是我對嗶哩嗶哩up主 霹靂吧啦Wz 的視頻的文字版學習筆記 感謝他對知識的分享 看一下這個main cnn.py的文件 那這里我為了方便 就直接從官方的torch vision這個庫當中導入一些我們常用的model 比如說我這里的例子是采用的mobile net v3 large這個模型 然后這里我將pretrain設…

微信小程序 純css畫儀表盤

剛看到設計稿的時候第一時間想到的就是用canvas來做這個儀表盤&#xff0c;雖然本人的畫布用的不是很好但還可以寫一寫&#x1f600;。話不多說直接上代碼。最后有純css方法 <!--wxml--> <canvas canvas-id"circle" class"circle" >// js dat…

MySQL 忘記root密碼后重置密碼操作

在忘記 MySQL 密碼的情況下&#xff0c;可以通過 --skip-grant-tables 關閉服務器的認證&#xff0c;然后重置 root 的密碼&#xff0c;具體操作步驟如下。 步驟 1)&#xff1a;關閉正在運行的 MySQL 服務。打開 cmd 進入 MySQL 的 bin 目錄。 步驟 2)&#xff1a;輸入mysqld -…

【Docker】容器數據持久化及容器互聯

容器數據持久化及容器互聯 一、Docker容器的數據管理1.1、什么是數據卷1.2、數據卷特點1.3、數據卷使用 二、Docker的數據卷容器2.1、什么是數據卷容器2.2、掛載數據卷容器方法 三、Docker數據卷的備份和還原3.1、數據備份方法3.2、數據還原方法 四、Docker容器互聯4.1、docker…

數據寶庫:深入探討數據隱私與安全的要義

寫在開頭 隨著數字時代的蓬勃發展&#xff0c;數據已成為當今社會的新型燃料。然而&#xff0c;正如能源需要保護和管理一樣&#xff0c;我們的數據同樣需要被妥善對待。本文將深入討論數據隱私和安全的不可忽視的重要性&#xff0c;并為您提供一些實用的基本措施和方法&#…

xcode ——Instrumets(網絡連接調試)使用

環境&#xff1a; instruments 使用只能在真機調試時使用&#xff0c;且真機系統必須ios15 點擊debug 按鈕——Network——Profile in Instruments 然后就可以看到如下面板 展開運行的項目&#xff0c;點擊session下的域名&#xff0c;下方回出現該域名下的網絡請求。點擊Deve…

管理類聯考——數學——真題篇——按題型分類——充分性判斷題——秒殺

題型結構 問題求解&#xff1a;通過計算求解&#xff0c;從五個選項中選出一個正確答案。條件充分性判斷&#xff1a;問所給的條件&#xff08;1&#xff09;&#xff08;2&#xff09;能否推出題設的結論&#xff0c;共有五個選項&#xff0c;從中選出正確的一個。&#xff0…

車聯網安全學習路標

1. 汽車和物聯網基礎知識 首先&#xff0c;你需要全面了解汽車和物聯網的基礎知識&#xff0c;包括汽車電子體系結構、車載通信技術&#xff08;如CAN、LIN、FlexRay、Ethernet&#xff09;以及物聯網的架構和通信協議&#xff08;如MQTT、CoAP&#xff09;。 2. 汽車網絡安全…

LCR 090. 打家劫舍 II(leetcode)動態規劃

文章目錄 前言一、題目分析二、算法原理1.狀態表示2.狀態轉移方程3.初始化4.填表順序5.返回值是什么 三、代碼實現總結 前言 在本文章中&#xff0c;我們將要詳細介紹一下LeetcodeLCR 090. 打家劫舍 II。采用動態規劃解決&#xff0c;這是一道經典的多狀態dp問題 一、題目分析…

人工智能從 DeepMind 到 ChatGPT ,從 2012 - 2024

本心、輸入輸出、結果 文章目錄 人工智能從 DeepMind 到 ChatGPT &#xff0c;從 2012 - 2024前言2010年&#xff1a;DeepMind誕生2012&#xff5e;2013年&#xff1a;谷歌重視AI發展&#xff0c;“拿下”Hinton2013&#xff5e;2014年&#xff1a;谷歌收購DeepMind2013年&…

stm32一種步進電機查表法驅動

文章目錄 一、定時器基礎頻率二、驅動原理三、關鍵代碼 對于stm32芯片來說&#xff0c;步進電機的驅動由于要在中斷中不斷計算下一次脈沖的時間而極其消耗算力&#xff0c;使用計算的方法對于芯片的算法消耗更高&#xff0c;特別是在f1這種算力比較低的芯片上&#xff0c;這時候…

Pipenv環境配置+Pytest運行

環境配置 使用Pipenv進行虛擬環境管理&#xff0c;Pipfile為依賴模塊管理文件。 安裝pipenv&#xff1a;brew install pipenv根項目根目錄下執行命令創建虛擬環境&#xff1a; pipenv install在Pycharm中指定項目運行的虛擬環境 &#xff1a;File->Settings->Project:-…

一文2500字使用Python進行GRPC和Dubbo協議的高級測試

01、GRPC測試 GRPC&#xff08;Google Remote Procedure Call&#xff09;是一種高性能、開源的遠程過程調用&#xff08;RPC&#xff09;框架&#xff0c;由 Google開發并基于Protocol Buffers&#xff08;protobuf&#xff09;進行通信。它使用了HTTP/2協議作為傳輸層&#…

C++11條件變量condition_variable

文章目錄 前言正文等待通知注意事項 結尾 前言 條件變量用于多線程中&#xff0c;其作用是在多線程間實現線程的等待、喚醒和通知機制&#xff0c;常配合互斥鎖&#xff08;std::mutex&#xff09;一起使用。它主要用于解決數據競爭問題>。 正文 條件變量只有五個函數&am…

PyQt6 QCalendarWidget日歷控件

?鋒哥原創的PyQt6視頻教程&#xff1a; 2024版 PyQt6 Python桌面開發 視頻教程(無廢話版) 玩命更新中~_嗶哩嗶哩_bilibili2024版 PyQt6 Python桌面開發 視頻教程(無廢話版) 玩命更新中~共計39條視頻&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面開發 視頻教程(無廢話…

快速實現入門HarmonyOS開發

本文檔適用于HarmonyOS應用開發的初學者。編寫兩個簡單的頁面&#xff0c;實現在第一個頁面點擊按鈕跳轉到第二個頁面。開始前&#xff0c;請參考下載與安裝軟件、配置開發環境和運行HelloWorld&#xff0c;完成開發工具的安裝和開發環境的配置。 開發Ability 概述&#xff1…