當前位置:首頁 » 編程語言 » 什麼是java鎖

什麼是java鎖

發布時間: 2024-09-23 02:22:29

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鎖有哪些種類,以及區別

鎖作為並發共享數據,保證一致性的工具,在JAVA平台有多種實現(如 synchronized 和 ReentrantLock等等 ) 。這些已經寫好提供的鎖為我們開發提供了便利,但是鎖的具體性質以及類型卻很少被提及。本系列文章將分析JAVA下常見的鎖名稱以及特性,為大家答疑解惑。
1、自旋鎖
自旋鎖是採用讓當前線程不停地的在循環體內執行實現的,當循環的條件被其他線程改變時 才能進入臨界區。如下

01 public class SpinLock {
02
03 private AtomicReference<Thread> sign =newAtomicReference<>();
04
05 public void lock(){
06 Thread current = Thread.currentThread();
07 while(!sign .compareAndSet(null, current)){
08 }
09 }
10
11 public void unlock (){
12 Thread current = Thread.currentThread();
13 sign .compareAndSet(current, null);
14 }
15 }
使用了CAS原子操作,lock函數將owner設置為當前線程,並且預測原來的值為空。unlock函數將owner設置為null,並且預測值為當前線程。
當有第二個線程調用lock操作時由於owner值不為空,導致循環一直被執行,直至第一個線程調用unlock函數將owner設置為null,第二個線程才能進入臨界區。
由於自旋鎖只是將當前線程不停地執行循環體,不進行線程狀態的改變,所以響應速度更快。但當線程數不停增加時,性能下降明顯,因為每個線程都需要執行,佔用CPU時間。如果線程競爭不激烈,並且保持鎖的時間段。適合使用自旋鎖。
註:該例子為非公平鎖,獲得鎖的先後順序,不會按照進入lock的先後順序進行。
Java鎖的種類以及辨析(二):自旋鎖的其他種類

鎖作為並發共享數據,保證一致性的工具,在JAVA平台有多種實現(如 synchronized 和 ReentrantLock等等 ) 。這些已經寫好提供的鎖為我們開發提供了便利,但是鎖的具體性質以及類型卻很少被提及。本系列文章將分析JAVA下常見的鎖名稱以及特性,為大家答疑解惑。

2.自旋鎖的其他種類
上篇我們講到了自旋鎖,在自旋鎖中 另有三種常見的鎖形式:TicketLock ,CLHlock 和MCSlock
Ticket鎖主要解決的是訪問順序的問題,主要的問題是在多核cpu上
01 package com.alipay.titan.dcc.dal.entity;
02
03 import java.util.concurrent.atomic.AtomicInteger;
04
05 public class TicketLock {
06 private AtomicInteger serviceNum = new AtomicInteger();
07 private AtomicInteger ticketNum = new AtomicInteger();
08 private static final ThreadLocal<Integer> LOCAL = new ThreadLocal<Integer>();
09
10 public void lock() {
11 int myticket = ticketNum.getAndIncrement();
12 LOCAL.set(myticket);
13 while (myticket != serviceNum.get()) {
14 }
15
16 }
17
18 public void unlock() {
19 int myticket = LOCAL.get();
20 serviceNum.compareAndSet(myticket, myticket + 1);
21 }
22 }
每次都要查詢一個serviceNum 服務號,影響性能(必須要到主內存讀取,並阻止其他cpu修改)。
CLHLock 和MCSLock 則是兩種類型相似的公平鎖,採用鏈表的形式進行排序,
01 importjava.util.concurrent.atomic.AtomicReferenceFieldUpdater;
02
03 public class CLHLock {
04 public static class CLHNode {
05 private volatile boolean isLocked = true;
06 }
07
08 @SuppressWarnings("unused")
09 private volatileCLHNode tail;
10 private static finalThreadLocal<CLHNode> LOCAL = new ThreadLocal<CLHNode>();
11 private static <CLHLock, CLHNode> UPDATER = AtomicReferenceFieldUpdater.newUpdater(CLHLock.class,
12 CLHNode.class,"tail");
13
14 public void lock() {
15 CLHNode node = new CLHNode();
16 LOCAL.set(node);
17 CLHNode preNode = UPDATER.getAndSet(this, node);
18 if (preNode != null) {
19 while (preNode.isLocked) {
20 }
21 preNode = null;
22 LOCAL.set(node);
23 }
24 }
25
26 public void unlock() {
27 CLHNode node = LOCAL.get();
28 if (!UPDATER.compareAndSet(this, node,null)) {
29 node.isLocked = false;
30 }
31 node = null;
32 }
33 }

CLHlock是不停的查詢前驅變數, 導致不適合在NUMA 架構下使用(在這種結構下,每個線程分布在不同的物理內存區域)
MCSLock則是對本地變數的節點進行循環。不存在CLHlock 的問題。
01 importjava.util.concurrent.atomic.AtomicReferenceFieldUpdater;
02
03 public class MCSLock {
04 public static class MCSNode {
05 volatile MCSNode next;
06 volatile boolean isLocked = true;
07 }
08
09 private static finalThreadLocal<MCSNode> NODE = new ThreadLocal<MCSNode>();
10 @SuppressWarnings("unused")
11 private volatileMCSNode queue;
12 private static <MCSLock, MCSNode> UPDATER = AtomicReferenceFieldUpdater.newUpdater(MCSLock.class,
13 MCSNode.class,"queue");
14
15 public void lock() {
16 MCSNode currentNode = new MCSNode();
17 NODE.set(currentNode);
18 MCSNode preNode = UPDATER.getAndSet(this, currentNode);
19 if (preNode != null) {
20 preNode.next = currentNode;
21 while (currentNode.isLocked) {
22
23 }
24 }
25 }
26
27 public void unlock() {
28 MCSNode currentNode = NODE.get();
29 if (currentNode.next == null) {
30 if (UPDATER.compareAndSet(this, currentNode, null)) {
31
32 } else {
33 while (currentNode.next == null) {
34 }
35 }
36 } else {
37 currentNode.next.isLocked = false;
38 currentNode.next = null;
39 }
40 }
41 }

⑶ 經常會聽到Java鎖這個詞,但給自己的感覺很朦朧,有辦法清楚的了解它嗎大蝦們給個建議!!!

java鎖機制Synchronized
打個比方:一個object就像一個大房子,大門永遠打開。房子里有很多房間(也就是方法)。這些房間有上鎖的(synchronized方法), 和不上鎖之分(普通方法)。房門口放著一把鑰匙(key),這把鑰匙可以打開所有上鎖的房間。另外我把所有想調用該對象方法的線程比喻成想進入這房子某個 房間的人。所有的東西就這么多了,下面我們看看這些東西之間如何作用的。

在此我們先來明確一下我們的前提條件。該對象至少有一個synchronized方法,否則這個key還有啥意義。當然也就不會有我們的這個主題了。

一個人想進入某間上了鎖的房間,他來到房子門口,看見鑰匙在那兒(說明暫時還沒有其他人要使用上鎖的房間)。於是他走上去拿到了鑰匙,並且按照自己 的計劃使用那些房間。注意一點,他每次使用完一次上鎖的房間後會馬上把鑰匙還回去。即使他要連續使用兩間上鎖的房間,中間他也要把鑰匙還回去,再取回來。

因此,普通情況下鑰匙的使用原則是:「隨用隨借,用完即還。」

這時其他人可以不受限制的使用那些不上鎖的房間,一個人用一間可以,兩個人用一間也可以,沒限制。但是如果當某個人想要進入上鎖的房間,他就要跑到大門口去看看了。有鑰匙當然拿了就走,沒有的話,就只能等了。

要是很多人在等這把鑰匙,等鑰匙還回來以後,誰會優先得到鑰匙?Not guaranteed。象前面例子里那個想連續使用兩個上鎖房間的傢伙,他中間還鑰匙的時候如果還有其他人在等鑰匙,那麼沒有任何保證這傢伙能再次拿到。 (JAVA規范在很多地方都明確說明不保證,象Thread.sleep()休息後多久會返回運行,相同優先權的線程那個首先被執行,當要訪問對象的鎖被 釋放後處於等待池的多個線程哪個會優先得到,等等。我想最終的決定權是在JVM,之所以不保證,就是因為JVM在做出上述決定的時候,絕不是簡簡單單根據 一個條件來做出判斷,而是根據很多條。而由於判斷條件太多,如果說出來可能會影響JAVA的推廣,也可能是因為知識產權保護的原因吧。SUN給了個不保證 就混過去了。無可厚非。但我相信這些不確定,並非完全不確定。因為計算機這東西本身就是按指令運行的。即使看起來很隨機的現象,其實都是有規律可尋。學過 計算機的都知道,計算機里隨機數的學名是偽隨機數,是人運用一定的方法寫出來的,看上去隨機罷了。另外,或許是因為要想弄的確定太費事,也沒多大意義,所 以不確定就不確定了吧。)

1、synchronized關鍵字的作用域有二種:
1)是某個對象實例內,synchronized aMethod(){}可以防止多個線程同時訪問這個對象的synchronized方法(如果一個對象有多個synchronized方法,只要一個線程訪問了其中的一個synchronized方法,其它線程不能同時訪問這個對象中任何一個synchronized方法)。這時,不同的對象實例的synchronized方法是不相干擾的。也就是說,其它線程照樣可以同時訪問相同類的另一個對象實例中的synchronized方法;
2)是某個類的范圍,synchronized static aStaticMethod{}防止多個線程同時訪問這個類中的synchronized static 方法。它可以對類的所有對象實例起作用。

2、除了方法前用synchronized關鍵字,synchronized關鍵字還可以用於方法中的某個區塊中,表示只對這個區塊的資源實行互斥訪問。用法是: synchronized(this){/*區塊*/},它的作用域是當前對象;

3、synchronized關鍵字是不能繼承的,也就是說,基類的方法synchronized f(){} 在繼承類中並不自動是synchronized f(){},而是變成了f(){}。繼承類需要你顯式的指定它的某個方法為synchronized方法;

synchronized的一個簡單例子

public class TextThread
{

/**
* @param args
*/
public static void main(String[] args)
{
// TODO 自動生成方法存根
TxtThread tt = new TxtThread();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
}

}
class TxtThread implements Runnable
{
int num = 100;
String str = new String();
public void run()
{
while (true)
{
synchronized(str)
{
if (num>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.getMessage();
}
System.out.println(Thread.currentThread().getName()+ "this is "+ num--);
}
}
}
}
}

上面的例子中為了製造一個時間差,也就是出錯的機會,使用了Thread.sleep(10)

總的說來,synchronized關鍵字可以作為函數的修飾符,也可作為函數內的語句,也就是平時說的同步方法和同步語句塊。如果再細的分類,synchronized可作用於instance變數、object reference(對象引用)、static函數和class literals(類名稱字面常量)身上。

⑷ JAVA鎖有哪些種類,以及區別

常見的Java鎖有下面這些:

  • 公平鎖/非公平鎖

  • 可重入鎖

  • 獨享鎖/共享鎖

  • 互斥鎖/讀寫鎖

  • 樂觀鎖/悲觀鎖

  • 分段鎖

  • 偏向鎖/輕量級鎖/重量級鎖

  • 自旋鎖

  • 這些分類並不是全是指鎖的狀態,有的指鎖的特性,有的指鎖的設計,下面總結的內容是對每個鎖的名詞進行一定的解釋。

    公平鎖/非公平鎖

    公平鎖是指多個線程按照申請鎖的順序來獲取鎖。
    非公平鎖是指多個線程獲取鎖的順序並不是按照申請鎖的順序,有可能後申請的線程比先申請的線程優先獲取鎖。有可能,會造成優先順序反轉或者飢餓現象。
    對於JavaReentrantLock而言,通過構造函數指定該鎖是否是公平鎖,默認是非公平鎖。非公平鎖的優點在於吞吐量比公平鎖大。
    對於Synchronized而言,也是一種非公平鎖。由於其並不像ReentrantLock是通過AQS的來實現線程調度,所以並沒有任何辦法使其變成公平鎖。

    可重入鎖

    可重入鎖又名遞歸鎖,是指在同一個線程在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖。說的有點抽象,下面會有一個代碼的示例。
    對於JavaReentrantLock而言, 他的名字就可以看出是一個可重入鎖,其名字是Re entrant Lock重新進入鎖。
    對於Synchronized而言,也是一個可重入鎖。可重入鎖的一個好處是可一定程度避免死鎖。

  • synchronized void setA() throws Exception{

  • Thread.sleep(1000);

  • setB();

  • }synchronized void setB() throws Exception{

  • Thread.sleep(1000);

  • }

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

    獨享鎖/共享鎖

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

    對於JavaReentrantLock而言,其是獨享鎖。但是對於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】公平所和非公平所。
公平鎖:是指按照申請鎖的順序來獲取鎖,
非公平所:線程獲取鎖的順序不一定按照申請鎖的順序來的。

//默認是不公平鎖,傳入true為公平鎖,否則為非公平鎖
ReentrantLock reentrantLock = new ReetrantLock();
1
2
【2】共享鎖和獨享鎖
獨享鎖:一次只能被一個線程所訪問
共享鎖:線程可以被多個線程所持有。
ReadWriteLock 讀鎖是共享鎖,寫鎖是獨享鎖。
【3】樂觀鎖和悲觀鎖。
樂觀鎖:對於一個數據的操作並發,是不會發生修改的。在更新數據的時候,會嘗試採用更新,不斷重入的方式,更新數據。
悲觀鎖:對於同一個數據的並發操作,是一定會發生修改的。因此對於同一個數據的並發操作,悲觀鎖採用加鎖的形式。悲觀鎖認為,不加鎖的操作一定會出問題,
【4】分段鎖
1.7及之前的concurrenthashmap。並發操作就是分段鎖,其思想就是讓鎖的粒度變小。
【5】偏向鎖是指一段同步代碼一直被一個線程所訪問,那麼該線程會自動獲取鎖。降低獲取鎖的代價
輕量級鎖
重量級鎖
【6】自旋鎖
自旋鎖

熱點內容
盤搜搜源碼 發布:2024-09-23 04:15:37 瀏覽:861
java四種線程池 發布:2024-09-23 04:13:49 瀏覽:717
凱撒加密c語言 發布:2024-09-23 04:07:37 瀏覽:257
ftp上傳模板 發布:2024-09-23 03:48:38 瀏覽:38
手機簡訊怎麼從安卓同步到ios 發布:2024-09-23 03:46:59 瀏覽:562
c語言百馬百擔 發布:2024-09-23 03:45:36 瀏覽:768
我的世界伺服器中主城傳送指令 發布:2024-09-23 03:40:55 瀏覽:38
xp系統如何知道電腦配置 發布:2024-09-23 03:36:53 瀏覽:580
chrome緩存頁面 發布:2024-09-23 03:28:35 瀏覽:980
安卓n81能裝什麼軟體 發布:2024-09-23 03:26:17 瀏覽:624