Java并發線程如何阻塞和喚醒?
每個對象都有兩個方法wait和notify,以及同步。
Java并發線程的阻塞和喚醒可以分為幾類:
1.同步是基于JVM的對象頭實現的。當多個線程競爭同一個關鍵資源時,它們會根據不同的鎖機制(旋轉鎖、輕/重鎖)進行阻塞和喚醒。
2.這里暫時跳過了notify/wait、yeild等基本機制,一般的實現原理是基于對象的同步隊列非常類似于后面的AQS。
3.并發組件的基本AQS側重于AQS(AbstractQueuedSynchronizer)。
因為這是jdk外包的基礎(比如Lock、BlockingQueue、CountdownLatch等。).
Aqs基本上是通過一個易變的變量狀態和一個等待隊列來實現的。在搶鎖時,CAS先修改狀態,失敗后放入等待隊列,通過LockSupport掛起線程。
當鎖的擁有者釋放鎖時,它會通過LockSupport喚醒等待隊列的后續節點,讓它再次嘗試搶鎖(CAS修改狀態),以此類推。
掌握AQS的原理對理解jdk中的很多并發組件很有幫助。
()方法:以毫秒為單位,使線程處于阻塞狀態,時間到了自動喚醒。
()和resume()方法:掛起和喚醒線程,suspende()使線程進入阻塞狀態,只有調用對應的resumee()時,線程才會進入可執行狀態。不建議這樣做,容易出現死鎖。
3.yield()方法:調用yield()的效果相當于調度器認為線程已經執行了足夠的時間,可以切換到另一個線程。
讓下面我們就來談談這三種。可以去csdn看看,了解一下其他的。
java的線程安全是什么?誰能一言以蔽之?
這真的可以不要用一句話來概括。我寫了一篇關于線程安全的長文,我提煉了下面這段話,基本夠理解了:
單線程不會有安全問題,多線程編程會有安全問題。根本問題在于是否存在關鍵資源競爭資源。如果多線程不會訪問競爭資源,就不會有安全問題,否則會處理。
什么是競爭資源,如下所示:
如果它們訪問它們上下文的資源,比如kafka消費分區工作線程訪問它們各自的存儲,它們將不會互相干擾;
如果在一個要執行的方法中只使用局部變量,它們不會互相干擾,因為它們位于各自的線程堆棧中;
如果執行的方法使用傳入的變量,即所謂的形參變量,取決于傳入的變量是否是對象。如果它只是一個普通的參數,它不沒關系。如果是對象,要看對象是不是同一個引用,不同的引用沒有關系。
如果在一個執行的方法中使用了相同的引用,不管它是傳入的還是外部的全局變量,比如log4的伐木工,唐不要擔心,因為log4已經完成了線程安全的編寫。
如果在執行的方法中使用了相同的引用:
I)但只是讀而不寫,讀與讀之間沒有,也不沒關系。
Ii)有所有的寫,但是寫不依賴于讀,也就是說,線程可以直接寫到覆蓋,而不需要獲得"最新"數據,這種情況無關緊要;
Iii)兩者都是寫的,寫的時候要看最新的資料,所以需要處理;