導航:首頁 > 編程語言 > javareentrantlock

javareentrantlock

發布時間:2023-02-23 03:07:30

java reentrantlock原理

你可以參考一下下面的自定義實現:
通過判斷線程的方式可以實現可重入鎖的構造
public class LockTest03 {
ReLock lock = new ReLock();
public void a() throws InterruptedException {
lock.lock();
System.out.println(lock.getHoldCount());
doSomething();
lock.unlock();
System.out.println(lock.getHoldCount());
}
//不可重入
public void doSomething() throws InterruptedException {
lock.lock();
System.out.println(lock.getHoldCount());
//...................
lock.unlock();
System.out.println(lock.getHoldCount());
}
public static void main(String[] args) throws InterruptedException {
LockTest03 test = new LockTest03();
test.a();
Thread.sleep(1000);
System.out.println(test.lock.getHoldCount());
}
}
// 可重入鎖
class ReLock{
//是否佔用
private boolean isLocked = false;
private Thread lockedBy = null; //存儲線程
private int holdCount = 0;
//使用鎖
public synchronized void lock() throws InterruptedException {
Thread t = Thread.currentThread();
while(isLocked && lockedBy != t) {
wait();
}

isLocked = true;
lockedBy = t;
holdCount ++;
}
//釋放鎖
public synchronized void unlock() {
if(Thread.currentThread() == lockedBy) {
holdCount --;
if(holdCount ==0) {
isLocked = false;
notify();
lockedBy = null;
}
}
}
public int getHoldCount() {
return holdCount;
}
}
有一個上下文的概念。

⑵ Java多線程之Atomic:原子變數與原子類

一 何謂Atomic?

Atomic一詞跟原子有點關系 後者曾被人認為是最小物質的單位 計算機中的Atomic是指不能分割成若幹部分的意思 如果一段代碼被認為是Atomic 則表示這段代碼在執行過程中 是不能被中斷的 通常來說 原子指令由硬體提供 供軟體來實現原子方法(某個線程進入該方法後 就不會被中斷 直到其執行完成)

在x 平台上 CPU提供了在指令執行期間對匯流排加鎖的手段 CPU晶元上有一條引線#HLOCK pin 如果匯編語言的程序中在一條指令前面加上前綴 LOCK 經過匯編以後的機器代碼就使CPU在執行這條指令的時候把#HLOCK pin的電位拉低 持續到這條指令結束時放開 從而把匯流排鎖住 這樣同一匯流排上別的CPU就暫時不能通過匯流排訪問內存了 保證了這條指令在多處理器環境中的原子性

二 ncurrent中的原子變數

無論是直接的還是間接的 幾乎 ncurrent 包中的所有類都使用原子變數 而不使用同步 類似 ConcurrentLinkedQueue 的類也使用原子變數直接實現無等待演算法 而類似 ConcurrentHashMap 的類使用 ReentrantLock 在需要時進行鎖定 然後 ReentrantLock 使用原子變數來維護等待鎖定的線程隊列

如果沒有 JDK 中的 JVM 改進 將無法構造這些類 這些改進暴露了(向類庫 而不是用戶類)介面來訪問硬體級的同步原語 然後 ncurrent 中的原子變數類和其他類向用戶類公開這些功能

ncurrent atomic的原子類

這個包裡面提供了一組原子類 其基本的特性就是在多線程環境下 當有多個線程同時執行這些類的實例包含的方法時 具有排他性 即當某個線程進入方法 執行其中的指令時 不會被其他線程打斷 而別的線程就像自旋鎖一樣 一直等到該方法執行完成 才由JVM從等待隊列中選擇一個另一個線程進入 這只是一種邏輯上的理解 實際上是藉助硬體的相關指令來實現的 不會阻塞線程(或者說只是在硬體級別上阻塞了) 其中的類可以分成 組

AtomicBoolean AtomicInteger AtomicLong AtomicReference

AtomicIntegerArray AtomicLongArray

AtomicLongFieldUpdater AtomicIntegerFieldUpdater AtomicReferenceFieldUpdater

AtomicMarkableReference AtomicStampedReference AtomicReferenceArray

其中AtomicBoolean AtomicInteger AtomicLong AtomicReference是類似的

首先AtomicBoolean AtomicInteger AtomicLong AtomicReference內部api是類似的 舉個AtomicReference的例子

使用AtomicReference創建線程安全的堆棧

Java代碼

public class LinkedStack<T> {

private AtomicReference<Node<T》 stacks = new AtomicReference<Node<T》()

public T push(T e) {

Node<T> oldNode newNode;

while (true) { //這里的處理非常的特別 也是必須如此的

oldNode = stacks get()

newNode = new Node<T>(e oldNode)

if (pareAndSet(oldNode newNode)) {

return e;

}

}

}

public T pop() {

Node<T> oldNode newNode;

while (true) {

oldNode = stacks get()

newNode = oldNode next;

if (pareAndSet(oldNode newNode)) {

return oldNode object;

}

}

}

private static final class Node<T> {

private T object;

private Node<T> next;

private Node(T object Node<T> next) {

this object = object;

this next = next;

}

}

}

然後關注欄位的原子更新

AtomicIntegerFieldUpdater<T>/AtomicLongFieldUpdater<T>/AtomicReferenceFieldUpdater<T V>是基於反射的原子更新欄位的值

相應的API也是非常簡

單的 但是也是有一些約束的

( )欄位必須是volatile類型的!volatile到底是個什麼東西 請查看

( )欄位的描述類型(修飾符public/protected/default/private)是與調用者與操作對象欄位的關系一致 也就是說調用者能夠直接操作對象欄位 那麼就可以反射進行原子操作 但是對於父類的欄位 子類是不能直接操作的 盡管子類可以訪問父類的欄位

( )只能是實例變數 不能是類變數 也就是說不能加static關鍵字

( )只能是可修改變數 不能使final變數 因為final的語義就是不可修改 實際上final的語義和volatile是有沖突的 這兩個關鍵字不能同時存在

( )對於AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long類型的欄位 不能修改其包裝類型(Integer/Long) 如果要修改包裝類型就需要使用AtomicReferenceFieldUpdater

在下面的例子中描述了操作的方法

[java]

import ncurrent atomic AtomicIntegerFieldUpdater;

public class AtomicIntegerFieldUpdaterDemo {

class DemoData{

public volatile int value = ;

volatile int value = ;

protected volatile int value = ;

private volatile int value = ;

}

AtomicIntegerFieldUpdater<DemoData> getUpdater(String fieldName) {

return AtomicIntegerFieldUpdater newUpdater(DemoData class fieldName)

}

void doit() {

DemoData data = new DemoData()

System out println( ==> +getUpdater( value ) getAndSet(data ))

System out println( ==> +getUpdater( value ) incrementAndGet(data))

System out println( ==> +getUpdater( value ) decrementAndGet(data))

System out println( true ==> +getUpdater( value ) pareAndSet(data ))

}

public static void main(String[] args) {

AtomicIntegerFieldUpdaterDemo demo = new AtomicIntegerFieldUpdaterDemo()

demo doit()

}

}

在上面的例子中DemoData的欄位value /value 對於AtomicIntegerFieldUpdaterDemo類是不可見的 因此通過反射是不能直接修改其值的

AtomicMarkableReference類描述的一個<Object Boolean>的對 可以原子的修改Object或者Boolean的值 這種數據結構在一些緩存或者狀態描述中比較有用 這種結構在單個或者同時修改Object/Boolean的時候能夠有效的提高吞吐量

AtomicStampedReference類維護帶有整數 標志 的對象引用 可以用原子方式對其進行更新 對比AtomicMarkableReference類的<Object Boolean> AtomicStampedReference維護的是一種類似<Object int>的數據結構 其實就是對對象(引用)的一個並發計數 但是與AtomicInteger不同的是 此數據結構可以攜帶一個對象引用(Object) 並且能夠對此對象和計數同時進行原子操作

在本文結尾會提到 ABA問題 而AtomicMarkableReference/AtomicStampedReference在解決 ABA問題 上很有用

三 Atomic類的作用

使得讓對單一數據的操作 實現了原子化

使用Atomic類構建復雜的 無需阻塞的代碼

訪問對 個或 個以上的atomic變數(或者對單個atomic變數進行 次或 次以上的操作)通常認為是需要同步的 以達到讓這些操作能被作為一個原子單元

無鎖定且無等待演算法

基於 CAS (pare and swap)的並發演算法稱為 無鎖定演算法 因為線程不必再等待鎖定(有時稱為互斥或關鍵部分 這取決於線程平台的術語) 無論 CAS 操作成功還是失敗 在任何一種情況中 它都在可預知的時間內完成 如果 CAS 失敗 調用者可以重試 CAS 操作或採取其他適合的操作

如果每個線程在其他線程任意延遲(或甚至失敗)時都將持續進行操作 就可以說該演算法是 無等待的 與此形成對比的是 無鎖定演算法要求僅 某個線程總是執行操作 (無等待的另一種定義是保證每個線程在其有限的步驟中正確計算自己的操作 而不管其他線程的操作 計時 交叉或速度 這一限制可以是系統中線程數的函數 例如 如果有 個線程 每個線程都執行一次CasCounter increment() 操作 最壞的情況下 每個線程將必須重試最多九次 才能完成增加 )

再過去的 年裡 人們已經對無等待且無鎖定演算法(也稱為 無阻塞演算法)進行了大量研究 許多人通用數據結構已經發現了無阻塞演算法 無阻塞演算法被廣泛用於操作系統和 JVM 級別 進行諸如線程和進程調度等任務 雖然它們的實現比較復雜 但相對於基於鎖定的備選演算法 它們有許多優點 可以避免優先順序倒置和死鎖等危險 競爭比較便宜 協調發生在更細的粒度級別 允許更高程度的並行機制等等

常見的

非阻塞的計數器Counter

非阻塞堆棧ConcurrentStack

lishixin/Article/program/Java/gj/201311/27474

⑶ java中共享鎖與無鎖的區別

獨享鎖是指該鎖一次只能被一個線程所持有。
共享鎖是指該鎖可被多個線程所持有。
對於Java ReentrantLock而言,其是獨享鎖。但是對於Lock的另一個實現類ReadWriteLock,其讀鎖是共享鎖,其寫鎖是獨享鎖。
讀鎖的共享鎖可保證並發讀是非常高效的,讀寫,寫讀 ,寫寫的過程是互斥的。
獨享鎖與共享鎖也是通過AQS來實現的,通過實現不同的方法,來實現獨享或者共享。
對於Synchronized而言,當然是獨享鎖。

⑷ java reentrantlock

java reentrantlock是什麼?一起來看下吧:

是一個可重入且獨占式的鎖,它具有與使用synchronized監視器鎖相同的基本行為和語義,但與synchronized關鍵字相比,它更靈活、更強大,增加了輪詢、超時、中斷等高級功能。ReentrantLock,顧名思義,它是支持可重入鎖的鎖,是一種遞歸無阻塞的同步機制。除此之外,該鎖還支持獲取鎖時的公平和非公平選擇。

ReentrantLock的內部類Sync繼承了AQS,分為公平鎖FairSync和非公平鎖NonfairSync。如果在絕對時間上,先對鎖進行獲取的請求你一定先被滿足,那麼這個鎖是公平的,反之,是不公平的。公平鎖的獲取,也就是等待時間最長的線程最優先獲取鎖,也可以說鎖獲取是順序的。ReentrantLock的公平與否,可以通過它的構造函數來決定。

事實上,公平鎖往往沒有非公平鎖的效率高,但是,並不是任何場景都是以TPS作為唯一指標,公平鎖能夠減少「飢餓」發生的概率,等待越久的請求越能夠得到優先滿足。

ReentrantLock是通過自定義同步器來實現鎖的獲取與釋放,我們以非公平鎖(默認)實現為例,對鎖的獲取和釋放進行詳解。

獲取鎖:
public ReentrantLock() {     sync = new NonfairSync(); }
即內部同步組件為非公平鎖,獲取鎖的代碼為:
public void lock() {     sync.lock(); }
釋放鎖:

成功獲取鎖的線程在完成業務邏輯之後,需要調用unlock()來釋放鎖:
public void unlock() {     sync.release(1); }
unlock()調用NonfairSync類的release(int)方法釋放鎖,release(int)方法是定義在AQS中的方法:
public final boolean release(int arg) {     if (tryRelease(arg)) {         Node h = head;         if (h != null && h.waitStatus != 0)             unparkSuccessor(h);         return true;     }     return false; }
tryRelease(int)是子類需要實現的方法:
protected final boolean tryRelease(int releases) {     // 計算新的狀態值     int c = getState() - releases;     // 判斷當前線程是否是持有鎖的線程,如果不是的話,拋出異常     if (Thread.currentThread() != getExclusiveOwnerThread())         throw new IllegalMonitorStateException();     boolean free = false;     // 新的狀態值是否為0,若為0,則表示該鎖已經完全釋放了,其他線程可以獲取同步狀態了     if (c == 0) {         free = true;         setExclusiveOwnerThread(null);     }     // 更新狀態值     setState(c);     return free; }
如果該鎖被獲取n次,那麼前(n-1)次tryRelease(int)方法必須返回false,只有同步狀態完全釋放了,才能返回true。可以看到,該方法將同步狀態是否為0作為最終釋放的條件,當狀態為0時,將佔有線程設為null,並返回true,表示釋放成功。

⑸ 請問java中的lock和synchronized區別是什麼

1、ReentrantLock 擁有Synchronized相同的並發性和內存語義,此外還多了 鎖投票,定時鎖等候和中斷鎖等候:

線程A和B都要獲取對象O的鎖定,假設A獲取了對象O鎖,B將等待A釋放對O的鎖定;

如果使用 synchronized ,如果A不釋放,B將一直等下去,不能被中斷;

如果 使用ReentrantLock,如果A不釋放,可以使B在等待了足夠長的時間以後,中斷等待,而干別的事情。

2、synchronized是在JVM層面上實現的,不但可以通過一些監控工具監控synchronized的鎖定,而且在代碼執行時出現異常,JVM會自動釋放鎖定,但是使用Lock則不行,lock是通過代碼實現的,要保證鎖定一定會被釋放,就必須將unLock()放到finally{}中。

3、在資源競爭不是很激烈的情況下,Synchronized的性能要優於ReetrantLock,但是在資源競爭很激烈的情況下,Synchronized的性能會下降幾十倍,但是ReetrantLock的性能能維持常態。

⑹ java 鎖有幾種

樂觀鎖/悲觀鎖

樂觀鎖與悲觀鎖不是指具體的什麼類型的鎖,而是指看待並發同步的角度。

悲觀鎖認為對於同一個數據的並發操作,一定是會發生修改的,哪怕沒有修改,也會認為修改。因此對於同一個數據的並發操作,悲觀鎖採取加鎖的形式。悲觀的認為,不加鎖的並發操作一定會出問題。
樂觀鎖則認為對於同一個數據的並發操作,是不會發生修改的。在更新數據的時候,會採用嘗試更新,不斷重新的方式更新數據。樂觀的認為,不加鎖的並發操作是沒有事情的。
從上面的描述我們可以看出,悲觀鎖適合寫操作非常多的場景,樂觀鎖適合讀操作非常多的場景,不加鎖會帶來大量的性能提升。
公平鎖/非公平鎖

公平鎖是指多個線程按照申請鎖的順序來獲取鎖。

非公平鎖是指多個線程獲取鎖的順序並不是按照申請鎖的順序,有可能後申請的線程比先申請的線程優先獲取鎖。

優點:在於吞吐量比公平鎖大。
缺點:可能會造成優先順序反轉或者某些線程飢餓現象(一直拿不到鎖)。
對於Java ReentrantLock而言,通過構造函數指定該鎖是否是公平鎖,默認是非公平鎖。
對於Synchronized而言,也是一種非公平鎖。由於其並不像ReentrantLock是通過AQS的來實現線程調度,所以並沒有任何辦法使其變成公平鎖。
可重入鎖

可重入鎖的概念是自己可以再次獲取自己的內部鎖。
舉個例子,比如一條線程獲得了某個對象的鎖,此時這個對象鎖還沒有釋放,當其再次想要獲取這個對象的鎖的時候還是可以獲取的(如果不可重入的鎖的話,此刻會造成死鎖)。說的更高深一點可重入鎖是一種遞歸無阻塞的同步機制。
對於Java ReentrantLock而言, 他的名字就可以看出是一個可重入鎖,其名字是Re entrant Lock重新進入鎖。
對於Synchronized而言,也是一個可重入鎖。可重入鎖的一個好處是可一定程度避免死鎖。
獨享鎖/共享鎖

獨享鎖是指該鎖一次只能被一個線程所持有。
共享鎖是指該鎖可被多個線程所持有。
對於Java ReentrantLock(互斥鎖)而言,其是獨享鎖。
但是對於Lock的另一個實現類ReadWriteLock(讀寫鎖),其讀鎖是共享鎖,其寫鎖是獨享鎖。讀鎖的共享鎖可保證並發讀是非常高效的,讀寫,寫讀 ,寫寫的過程是互斥的。
對於Synchronized而言,當然是獨享鎖。
分段鎖

分段鎖其實是一種鎖的設計,並不是具體的一種鎖。對於ConcurrentHashMap而言,其並發的實現就是通過分段鎖的形式來實現高效的並發操作。

我們以ConcurrentHashMap來說一下分段鎖的含義以及設計思想,ConcurrentHashMap中的分段鎖稱為Segment,它即類似於HashMap(JDK7與JDK8中HashMap的實現)的結構,即內部擁有一個Entry數組,數組中的每個元素又是一個鏈表;同時又是一個ReentrantLock(Segment繼承了ReentrantLock)。
當需要put元素的時候,並不是對整個hashmap進行加鎖,而是先通過hashcode來知道他要放在那一個分段中,然後對這個分段進行加鎖,所以當多線程put的時候,只要不是放在一個分段中,就實現了真正的並行的插入。
但是,在統計size的時候,可就是獲取hashmap全局信息的時候,就需要獲取所有的分段鎖才能統計。
分段鎖的設計目的是細化鎖的粒度,當操作不需要更新整個數組的時候,就僅僅針對數組中的一項進行加鎖操作。
互斥鎖:

無法獲取瑣時,進線程立刻放棄剩餘的時間片並進入阻塞(或者說掛起)狀態,同時保存寄存器和程序計數器的內容(保存現場,上下文切換的前半部分),當可以獲取鎖時,進線程激活,等待被調度進CPU並恢復現場(上下文切換下半部分)

上下文切換會帶來數十微秒的開銷,不要在性能敏感的地方用互斥鎖
讀寫鎖:

1)多個讀者可以同時進行讀
2)寫者必須互斥(只允許一個寫者寫,也不能讀者寫者同時進行)
3)寫者優先於讀者(一旦有寫者,則後續讀者必須等待,喚醒時優先考慮寫者)
自旋鎖:

自旋鎖是指嘗試獲取鎖的線程不會立即阻塞,而是採用循環的方式去嘗試獲取鎖,這樣的好處是減少線程上下文切換的消耗,缺點是循環會消耗CPU。

⑺ Java中ReentrantLock能否實現在同一個類中兩個方法之間互斥

importjava.util.concurrent.locks.ReentrantLock;

publicclassTest{
=newReentrantLock();

publicvoidt1(){
if(lock.tryLock()){
System.out.println("t1");
}
}
publicvoidt2(){
if(lock.tryLock()){
System.out.println("t2");
}
}
}

大致思路就是用同一個lock 來鎖住兩個方法,當t1正在執行時,t2就直接跳過不會執行了

⑻ Java鎖有哪些種類,以及區別

一、公平鎖/非公平鎖

公平鎖是指多個線程按照申請鎖的順序來獲取鎖。

非公平鎖是指多個線程獲取鎖的順序並不是按照申請鎖的順序,有可能後申請的線程比先申請的線程優先獲取鎖。有可能,會造成優先順序反轉或者飢餓現象。

對於Java ReentrantLock而言,通過構造函數指定該鎖是否是公平鎖,默認是非公平鎖。非公平鎖的優點在於吞吐量比公平鎖大。

對於Synchronized而言,也是一種非公平鎖。由於其並不像ReentrantLock是通過AQS的來實現線程調度,所以並沒有任何辦法使其變成公平鎖。

二、可重入鎖

可重入鎖又名遞歸鎖,是指在同一個線程在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖。說的有點抽象,下面會有一個代碼的示例。

對於Java ReentrantLock而言, 他的名字就可以看出是一個可重入鎖,其名字是Re entrant Lock重新進入鎖。

對於Synchronized而言,也是一個可重入鎖。可重入鎖的一個好處是可一定程度避免死鎖。

synchronized void setA() throws Exception{

Thread.sleep(1000);

setB();

}

synchronized void setB() throws Exception{

Thread.sleep(1000);

}

上面的代碼就是一個可重入鎖的一個特點,如果不是可重入鎖的話,setB可能不會被當前線程執行,可能造成死鎖。

三、獨享鎖/共享鎖

獨享鎖是指該鎖一次只能被一個線程所持有。

共享鎖是指該鎖可被多個線程所持有。

對於Java
ReentrantLock而言,其是獨享鎖。但是對於Lock的另一個實現類ReadWriteLock,其讀鎖是共享鎖,其寫鎖是獨享鎖。

讀鎖的共享鎖可保證並發讀是非常高效的,讀寫,寫讀 ,寫寫的過程是互斥的。

獨享鎖與共享鎖也是通過AQS來實現的,通過實現不同的方法,來實現獨享或者共享。

對於Synchronized而言,當然是獨享鎖。

四、互斥鎖/讀寫鎖

上面講的獨享鎖/共享鎖就是一種廣義的說法,互斥鎖/讀寫鎖就是具體的實現。

互斥鎖在Java中的具體實現就是ReentrantLock

讀寫鎖在Java中的具體實現就是ReadWriteLock

五、樂觀鎖/悲觀鎖

樂觀鎖與悲觀鎖不是指具體的什麼類型的鎖,而是指看待並發同步的角度。

悲觀鎖認為對於同一個數據的並發操作,一定是會發生修改的,哪怕沒有修改,也會認為修改。因此對於同一個數據的並發操作,悲觀鎖採取加鎖的形式。悲觀的認為,不加鎖的並發操作一定會出問題。

樂觀鎖則認為對於同一個數據的並發操作,是不會發生修改的。在更新數據的時候,會採用嘗試更新,不斷重新的方式更新數據。樂觀的認為,不加鎖的並發操作是沒有事情的。

從上面的描述我們可以看出,悲觀鎖適合寫操作非常多的場景,樂觀鎖適合讀操作非常多的場景,不加鎖會帶來大量的性能提升。

悲觀鎖在Java中的使用,就是利用各種鎖。

樂觀鎖在Java中的使用,是無鎖編程,常常採用的是CAS演算法,典型的例子就是原子類,通過CAS自旋實現原子操作的更新。

六、分段鎖

分段鎖其實是一種鎖的設計,並不是具體的一種鎖,對於ConcurrentHashMap而言,其並發的實現就是通過分段鎖的形式來實現高效的並發操作。

我們以ConcurrentHashMap來說一下分段鎖的含義以及設計思想,ConcurrentHashMap中的分段鎖稱為Segment,它即類似於HashMap(JDK7與JDK8中HashMap的實現)的結構,即內部擁有一個Entry數組,數組中的每個元素又是一個鏈表;同時又是一個ReentrantLock(Segment繼承了ReentrantLock)。

當需要put元素的時候,並不是對整個hashmap進行加鎖,而是先通過hashcode來知道他要放在那一個分段中,然後對這個分段進行加鎖,所以當多線程put的時候,只要不是放在一個分段中,就實現了真正的並行的插入。

但是,在統計size的時候,可就是獲取hashmap全局信息的時候,就需要獲取所有的分段鎖才能統計。

分段鎖的設計目的是細化鎖的粒度,當操作不需要更新整個數組的時候,就僅僅針對數組中的一項進行加鎖操作。

七、偏向鎖/輕量級鎖/重量級鎖

這三種鎖是指鎖的狀態,並且是針對Synchronized。在Java
5通過引入鎖升級的機制來實現高效Synchronized。這三種鎖的狀態是通過對象監視器在對象頭中的欄位來表明的。

偏向鎖是指一段同步代碼一直被一個線程所訪問,那麼該線程會自動獲取鎖。降低獲取鎖的代價。

輕量級鎖是指當鎖是偏向鎖的時候,被另一個線程所訪問,偏向鎖就會升級為輕量級鎖,其他線程會通過自旋的形式嘗試獲取鎖,不會阻塞,提高性能。

重量級鎖是指當鎖為輕量級鎖的時候,另一個線程雖然是自旋,但自旋不會一直持續下去,當自旋一定次數的時候,還沒有獲取到鎖,就會進入阻塞,該鎖膨脹為重量級鎖。重量級鎖會讓其他申請的線程進入阻塞,性能降低。

八、自旋鎖

在Java中,自旋鎖是指嘗試獲取鎖的線程不會立即阻塞,而是採用循環的方式去嘗試獲取鎖,這樣的好處是減少線程上下文切換的消耗,缺點是循環會消耗CPU。

典型的自旋鎖實現的例子,可以參考自旋鎖的實現

⑼ java並發常識

1.java並發編程是什麼
1, 保證線程安全的三種方法: a, 不要跨線程訪問共享變數b, 使共享變數是final類型的c, 將共享變數的操作加上同步 2, 一開始就將類設計成線程安全的, 比在後期重新修復它,更容易。

3, 編寫多線程程序, 首先保證它是正確的, 其次再考慮性能。 4, 無狀態或只讀對象永遠是線程安全的。

5, 不要將一個共享變數 *** 在多線程環境下(無同步或不可變性保護) 6, 多線程環境下的延遲載入需要同步的保護, 因為延遲載入會造成對象重復實例化 7, 對於volatile聲明的數值類型變數進行運算, 往往是不安全的(volatile只能保證可見性,不能保證原子性)。 詳見volatile原理與技巧中, 臟數據問題討論。

8, 當一個線程請求獲得它自己佔有的鎖時(同一把鎖的嵌套使用), 我們稱該鎖為可重入鎖。在jdk1。

5並發包中, 提供了可重入鎖的java實現-ReentrantLock。 9, 每個共享變數,都應該由一個唯一確定的鎖保護。

創建與變數相同數目的ReentrantLock, 使他們負責每個變數的線程安全。 10,雖然縮小同步塊的范圍, 可以提升系統性能。

但在保證原子性的情況下, 不可將原子操作分解成多個synchronized塊。 11, 在沒有同步的情況下, 編譯器與處理器運行時的指令執行順序可能完全出乎意料。

原因是, 編譯器或處理器為了優化自身執行效率, 而對指令進行了的重排序(reordering)。 12, 當一個線程在沒有同步的情況下讀取變數, 它可能會得到一個過期值, 但是至少它可以看到那個線程在當時設定的一個真實數值。

而不是憑空而來的值。 這種安全保證, 稱之為最低限的安全性(out-of-thin-air safety) 在開發並發應用程序時, 有時為了大幅度提高系統的吞吐量與性能, 會採用這種無保障的做法。

但是針對, 數值的運算, 仍舊是被否決的。 13, volatile變數,只能保證可見性, 無法保證原子性。

14, 某些耗時較長的網路操作或IO, 確保執行時, 不要佔有鎖。 15, 發布(publish)對象, 指的是使它能夠被當前范圍之外的代碼所使用。

(引用傳遞)對象逸出(escape), 指的是一個對象在尚未准備好時將它發布。 原則: 為防止逸出, 對象必須要被完全構造完後, 才可以被發布(最好的解決方式是採用同步) this關鍵字引用對象逸出 例子: 在構造函數中, 開啟線程, 並將自身對象this傳入線程, 造成引用傳遞。

而此時, 構造函數尚未執行完, 就會發生對象逸出了。 16, 必要時, 使用ThreadLocal變數確保線程封閉性(封閉線程往往是比較安全的, 但一定程度上會造成性能損耗)封閉對象的例子在實際使用過程中, 比較常見, 例如 hibernate openSessionInView機制, jdbc的connection機制。

17, 單一不可變對象往往是線程安全的(復雜不可變對象需要保證其內部成員變數也是不可變的)良好的多線程編程習慣是: 將所有的域都聲明為final, 除非它們是可變的。
2.Java線程並發協作是什麼
線程發生死鎖可能性很小,即使看似可能發生死鎖的代碼,在運行時發生死鎖的可能性也是小之又小。

發生死鎖的原因一般是兩個對象的鎖相互等待造成的。 在《Java線程:線程的同步與鎖》一文中,簡述死鎖的概念與簡單例子,但是所給的例子是不完整的,這里給出一個完整的例子。

/** * Java線程:並發協作-死鎖 * * @author Administrator 2009-11-4 22:06:13 */ public class Test { public static void main(String[] args) { DeadlockRisk dead = new DeadlockRisk(); MyThread t1 = new MyThread(dead, 1, 2); MyThread t2 = new MyThread(dead, 3, 4); MyThread t3 = new MyThread(dead, 5, 6); MyThread t4 = new MyThread(dead, 7, 8); t1。 start(); t2。

start(); t3。start(); t4。

start(); } } class MyThread extends Thread { private DeadlockRisk dead; private int a, b; MyThread(DeadlockRisk dead, int a, int b) { this。 dead = dead; this。

a = a; this。b = b; } @Override public void run() { dead。

read(); dead。write(a, b); } } class DeadlockRisk { private static class Resource { public int value; }。
3.如何學習Java高並發
1.學習 *** 並發框架的使用,如ConcurrentHashMAP,CopyOnWriteArrayList/Set等2.幾種並發鎖的使用以及線程同步與互斥,如ReentainLock,synchronized,Lock,CountDownLatch,Semaphore等3.線程池如Executors,ThreadPoolExecutor等4.Runable,Callable,RescureTask,Future,FutureTask等5.Fork-Join框架以上基本包含完了,如有缺漏請原諒。
4.並發編程的Java抽象有哪些呢
一、機器和OS級別抽象 (1)馮諾伊曼模型 經典的順序化計算模型,貌似可以保證順序化一致性,但是沒有哪個現代的多處理架構會提供順序一致性,馮氏模型只是現代多處理器行為的模糊近似。

這個計算模型,指令或者命令列表改變內存變數直接契合命令編程泛型,它以顯式的演算法為中心,這和聲明式編程泛型有區別。 就並發編程來說,會顯著的引入時間概念和狀態依賴 所以所謂的函數式編程可以解決其中的部分問題。

(2)進程和線程 進程抽象運行的程序,是操作系統資源分配的基本單位,是資源cpu,內存,IO的綜合抽象。 線程是進程式控制制流的多重分支,它存在於進程里,是操作系統調度的基本單位,線程之間同步或者非同步執行,共享進程的內存地址空間。

(3)並發與並行 並發,英文單詞是concurrent,是指邏輯上同時發生,有人做過比喻,要完成吃完三個饅頭的任務,一個人可以這個饅頭咬一口,那個饅頭咬一口,這樣交替進行,最後吃完三個饅頭,這就是並發,因為在三個饅頭上同時發生了吃的行為,如果只是吃完一個接著吃另一個,這就不是並發了,是排隊,三個饅頭如果分給三個人吃,這樣的任務完成形式叫並行,英文單詞是parallel。 回到計算機概念,並發應該是單CPU時代或者單核時代的說法,這個時候CPU要同時完成多任務,只能用時間片輪轉,在邏輯上同時發生,但在物理上是串列的。

現在大多數計算機都是多核或者多CPU,那麼現在的多任務執行方式就是物理上並行的。 為了從物理上支持並發編程,CPU提供了相應的特殊指令,比如原子化的讀改寫,比較並交換。

(4)平台內存模型 在可共享內存的多處理器體系結構中,每個處理器都有它自己的緩存,並且周期性的與主存同步,為什麼呢?因為處理器通過降低一致性來換取性能,這和CAP原理通過降低一致性來獲取伸縮性有點類似,所以大量的數據在CPU的寄存器中被計算,另外CPU和編譯器為了性能還會亂序執行,但是CPU會提供存儲關卡指令來保證存儲的同步,各種平台的內存模型或者同步指令可能不同,所以這里必須介入對內存模型的抽象,JMM就是其中之一。 二、編程模型抽象 (1)基於線程模型 (2)基於Actor模型 (3)基於STM軟體事務內存 …… Java體系是一個基於線程模型的本質編程平台,所以我們主要討論線程模型。

三、並發單元抽象 大多數並發應用程序都是圍繞執行任務進行管理的,任務是抽象,離散的工作單元,所以編寫並發程序,首要工作就是提取和分解並行任務。 一旦任務被抽象出來,他們就可以交給並發編程平台去執行,同時在任務抽象還有另一個重要抽象,那就是生命周期,一個任務的開始,結束,返回結果,都是生命周期中重要的階段。

那麼編程平台必須提供有效安全的管理任務生命周期的API。 四、線程模型 線程模型是Java的本質模型,它無所不在,所以Java開發必須搞清楚底層線程調度細節,不搞清楚當然就會有struts1,struts2的原理搞不清楚的基本災難(比如在struts2的action中塞入狀態,把struts2的action配成單例)。

用線程來抽象並發編程,是比較低級別的抽象,所以難度就大一些,難度級別會根據我們的任務特點有以下幾個類別 (1)任務非常獨立,不共享,這是最理想的情況,編程壓力為0。 (2)共享數據,壓力開始增大,必須引入鎖,Volatile變數,問題有活躍度和性能危險。

(3)狀態依賴,壓力再度增大,這時候我們基本上都是求助jdk 提供的同步工具。 五、任務執行 任務是一個抽象體,如果被抽象了出來,下一步就是交給編程平台去執行,在Java中,描述任務的一個基本介面是Runnable,可是這個抽象太有限了,它不能返回值和拋受檢查異常,所以Jdk5。

0有另外一個高級抽象Callable。 任務的執行在Jdk中也是一個底級別的Thread,線程有好處,但是大量線程就有大大的壞處,所以如果任務量很多我們並不能就創建大量的線程去服務這些任務,那麼Jdk5。

0在任務執行上做了抽象,將任務和任務執行隔離在介面背後,這樣我們就可以引入比如線程池的技術來優化執行,優化線程的創建。 任務是有生命周期的,所以Jdk5。

0提供了Future這個對象來描述對象的生命周期,通過這個future可以取到任務的結果甚至取消任務。 六、鎖 當然任務之間共享了數據,那麼要保證數據的安全,必須提供一個鎖機制來協調狀態,鎖讓數據訪問原子,但是引入了串列化,降低了並發度,鎖是降低程序伸縮性的原罪,鎖是引入上下文切換的主要原罪,鎖是引入死鎖,活鎖,優先順序倒置的絕對原罪,但是又不能沒有鎖,在Java中,鎖是一個對象,鎖提供原子和內存可見性,Volatile變數提供內存可見性不提供原子,原子變數提供可見性和原子,通過原子變數可以構建無鎖演算法和無鎖數據結構,但是這需要高高手才可以辦到。
5.Java高並發入門要怎麼學習
1、如果不使用框架,純原生Java編寫,是需要了解Java並發編程的,主要就是學習Doug Lea開發的那個java.util.concurrent包下面的API;2、如果使用框架,那麼我的理解,在代碼層面確實不會需要太多的去關注並發問題,反而是由於高並發會給系統造成很大壓力,要在緩存、資料庫操作上要多加考慮。

3、但是即使是使用框架,在工作中還是會用到多線程,就拿常見的CRUD介面來說,比如一個非常耗時的save介面,有多耗時呢?我們假設整個save執行完要10分鍾,所以,在save的時候,就需要採用非同步的方式,也就是單獨用一個線程去save,然後直接給前端返回200。
6.Java如何進行並發多連接socket編程呢
Java多個客戶端同時連接服務端,在現實生活中用得比較多。

同時執行多項任務,第一想到的當然是多線程了。下面用多線程來實現並發多連接。

import java。。

*; import java。io。

*; public class ThreadServer extends Thread { private Socket client; public ThreadServer(Socket c) { this。 client=c; } public void run() { try { BufferedReader in=new BufferedReader(new InputStreamReader(client。

getInputStream())); PrintWriter out=new PrintWriter(client。 getOutputStream()); Mutil User but can't parallel while (true) { String str=in。

readLine(); System。out。

println(str); out。 println("has receive。

"); out。

flush(); if (str。equals("end")) break; } client。

close(); } catch (IOException ex) { } finally { } } public static void main(String[] args)throws IOException { ServerSocket server=new ServerSocket(8000); while (true) { transfer location change Single User or Multi User ThreadServer mu=new ThreadServer(server。 accept()); mu。

start(); } } }J。
7.如何掌握java多線程,高並發,大數據方面的技能
線程:同一類線程共享代碼和數據空間,每個線程有獨立的運行棧和程序計數器(PC),線程切換開銷小。

(線程是cpu調度的最小單位)線程和進程一樣分為五個階段:創建、就緒、運行、阻塞、終止。多進程是指操作系統能同時運行多個任務(程序)。

多線程是指在同一程序中有多個順序流在執行。在java中要想實現多線程,有兩種手段,一種是繼續Thread類,另外一種是實現Runable介面.(其實准確來講,應該有三種,還有一種是實現Callable介面,並與Future、線程池結合使用。
8.java工程師需要掌握哪些知識
1.Core Java,就是Java基礎、JDK的類庫,很多童鞋都會說,JDK我懂,但是懂還不足夠,知其然還要知其所以然,JDK的源代碼寫的非常好,要經常查看,對使用頻繁的類,比如String, *** 類(List,Map,Set)等數據結構要知道它們的實現,不同的 *** 類有什麼區別,然後才能知道在一個具體的場合下使用哪個 *** 類更適合、更高效,這些內容直接看源代碼就OK了2.多線程並發編程,現在並發幾乎是寫服務端程序必須的技術,那對Java中的多線程就要有足夠的熟悉,包括對象鎖機制、synchronized關鍵字,concurrent包都要非常熟悉,這部分推薦你看看《Java並發編程實踐》這本書,講解的很詳細3.I/O,Socket編程,首先要熟悉Java中Socket編程,以及I/O包,再深入下去就是Java NIO,再深入下去是操作系統底層的Socket實現,了解Windows和Linux中是怎麼實現socket的4.JVM的一些知識,不需要熟悉,但是需要了解,這是Java的本質,可以說是Java的母體, 了解之後眼界會更寬闊,比如Java內存模型(會對理解Java鎖、多線程有幫助)、位元組碼、JVM的模型、各種垃圾收集器以及選擇、JVM的執行參數(優化JVM)等等,這些知識在《深入Java虛擬機》這本書中都有詳盡的解釋,或者去oracle網站上查看具體版本的JVM規范.5.一些常用的設計模式,比如單例、模板方法、代理、適配器等等,以及在Core Java和一些Java框架里的具體場景的實現,這個可能需要慢慢積累,先了解有哪些使用場景,見得多了,自己就自然而然會去用。

6.常用資料庫(Oracle、MySQL等)、SQL語句以及一般的優化7.JavaWeb開發的框架,比如Spring、iBatis等框架,同樣他們的原理才是最重要的,至少要知道他們的大致原理。8.其他一些有名的用的比較多的開源框架和包,ty網路框架,Apache mon的N多包,Google的Guava等等,也可以經常去Github上找一些代碼看看。

暫時想到的就這么多吧,1-4條是Java基礎,全部的這些知識沒有一定的時間積累是很難搞懂的,但是了解了之後會對Java有個徹底的了解,5和6是需要學習的額外技術,7-8是都是基於1-4條的,正所謂萬變不離其宗,前4條就是Java的靈魂所在,希望能對你有所幫助9.(補充)學會使用Git。如果你還在用SVN的話,趕緊投入Git的懷抱吧。
9.java 多線程的並發到底是什麼意思
一、多線程1、操作系統有兩個容易混淆的概念,進程和線程。

進程:一個計算機程序的運行實例,包含了需要執行的指令;有自己的獨立地址空間,包含程序內容和數據;不同進程的地址空間是互相隔離的;進程擁有各種資源和狀態信息,包括打開的文件、子進程和信號處理。線程:表示程序的執行流程,是CPU調度執行的基本單位;線程有自己的程序計數器、寄存器、堆棧和幀。

同一進程中的線程共用相同的地址空間,同時共享進進程鎖擁有的內存和其他資源。2、Java標准庫提供了進程和線程相關的API,進程主要包括表示進程的java.lang.Process類和創建進程的java.lang.ProcessBuilder類;表示線程的是java.lang.Thread類,在虛擬機啟動之後,通常只有Java類的main方法這個普通線程運行,運行時可以創建和啟動新的線程;還有一類守護線程(damon thread),守護線程在後台運行,提供程序運行時所需的服務。

當虛擬機中運行的所有線程都是守護線程時,虛擬機終止運行。3、線程間的可見性:一個線程對進程 *** 享的數據的修改,是否對另一個線程可見可見性問題:a、CPU採用時間片輪轉等不同演算法來對線程進行調度[java] view plainpublic class IdGenerator{ private int value = 0; public int getNext(){ return value++; } } 對於IdGenerator的getNext()方法,在多線程下不能保證返回值是不重復的:各個線程之間相互競爭CPU時間來獲取運行機會,CPU切換可能發生在執行間隙。

以上代碼getNext()的指令序列:CPU切換可能發生在7條指令之間,多個getNext的指令交織在一起。

⑽ java reentrantlock用在什麼地方

1.ReentrantLock 類實現了 Lock ,它擁有與 synchronized 相同的並發性和內存語義,但是添加了類似鎖投票、定時鎖等候和可中斷鎖等候的一些特性。此外,它還提供了在激烈爭用情況下更佳的性能。(換句話說,當許多線程都想訪問共享資源時,JVM 可以花更少的時候來調度線程,把更多時間用在執行線程上。)
2.reentrant 鎖意味著什麼呢?簡單來說,它有一個與鎖相關的獲取計數器,如果擁有鎖的某個線程再次得到鎖,那麼獲取計數器就加1,然後鎖需要被釋放兩次才能獲得真正釋放。這模仿了 synchronized 的語義;如果線程進入由線程已經擁有的監控器保護的 synchronized 塊,就允許線程繼續進行,當線程退出第二個(或者後續) synchronized塊的時候,不釋放鎖,只有線程退出它進入的監控器保護的第一個 synchronized 塊時,才釋放鎖。
3.lock 必須在 finally 塊中釋放。否則,如果受保護的代碼將拋出異常,鎖就有可能永遠得不到釋放!這一點區別看起來可能沒什麼,但是實際上,它極為重要。忘記在 finally 塊中釋放鎖,可能會在程序中留下一個定時炸彈,當有一天炸彈爆炸時,您要花費很大力氣才有找到源頭在哪。而使用同步,JVM 將確保鎖會獲得自動釋放。

閱讀全文

與javareentrantlock相關的資料

熱點內容
桌面文件全部加密 瀏覽:401
6s怎麼外接u盤需要什麼app 瀏覽:131
linux查看文件許可權命令 瀏覽:685
安卓手游存檔怎麼用 瀏覽:761
linuxyum安裝ftp 瀏覽:690
村委會主任可以推行政命令嗎 瀏覽:102
電腦文件夾封面多張圖片 瀏覽:263
網吧總伺服器叫什麼 瀏覽:922
多個演算法解決同一個問題 瀏覽:455
小車解壓後我的購車發票呢 瀏覽:977
做app開發用什麼雲伺服器 瀏覽:177
linux網卡子介面 瀏覽:985
21歲職高畢業學程序員怎麼學 瀏覽:321
vs如何對單個文件編譯 瀏覽:6
為什麼有的電腦不能安裝python 瀏覽:75
金蝶迷你版加密狗檢測到過期 瀏覽:186
硬體描述語言編譯結果 瀏覽:655
程序員逆天改命 瀏覽:19
金斗雲伺服器 瀏覽:447
港口工程pdf 瀏覽:770