本文目錄一覽:
- 1、如何使用java的鎖機制
- 2、java Lock鎖為什麼不直接使用
- 3、Java中lock類該怎麼用啊?可以完全代替synchronize嗎?
- 4、關於java的lock和condition
- 5、Java中Lock,tryLock,lockInterruptibly有什麼區別
- 6、深入研究 Java Synchronize 和 Lock 的區別與用法
如何使用java的鎖機制
可以在臨界區代碼開始的位置執行Lock類的lock方法,為代碼塊加鎖,而在臨界區的出口使用相同Lock實例的unlock方法,釋放臨界區資源。
Demo2-12中,主線程先創建了一個lockTest對象test,然後將相同的test對象交給兩個不同的線程執行。子線程1獲取到了lock後,開始執行before sleep輸出語句,遇到sleep後,線程1阻塞將會放棄執行權,這時線程2可以獲取執行權,當線程2執行lock方法時,發現鎖已經被別的線程獲取,所以線程2阻塞等待lock的釋放。線程1從sleep中被喚醒後,將繼續執行after sleep語句,之後釋放了鎖,此時線程2從鎖等待中被喚醒,執行臨近區的內容,因此Demo2-12的輸出是先線程1的兩條語句,之後才輸出線程2的兩條語句。而Demo2-13在沒有鎖的保護下,程序無法保證先將線程1的兩條語句輸出後再執行線程2的輸出,因此,Demo2-13的輸出結果是交叉的。
java Lock鎖為什麼不直接使用
主要為了多線程訪問共享資源時,保證只能有一個線程操作資源,比如說一個servlet中對根據參數 一個公共變數設置值 ,如果不採用lock那麼在並發訪問時就無法保證每個線程中公共變數設置的值都是各自線程的,在後續的應用中變數的值可能會錯亂,加了lock之後就保證了在一個線程中從頭到尾都是一致的
Java中lock類該怎麼用啊?可以完全代替synchronize嗎?
1、上鎖(漂亮的寫法是先判斷是否鎖被佔用)
2、你要執行的命令(比如讀取io和資料庫 釋放相關資源)
3、釋放鎖
然後別的地方就是重複以上三步的過程
synchronize就是把1和3替換成了{ }
完全替代到不一定 畢竟synchronize使用起來簡單明了
關於java的lock和condition
1、在某些情況下,當內部鎖非常不靈活時,顯式鎖就可以派上用場。內部條件隊列有一些缺陷,每個內部鎖只能有一個與之相關聯的條件隊列。
2、使用顯式的Lock和Condition的實現類提供了一個比內部鎖和條件隊列更加靈活的選擇。一個Condition和一個單獨的Lock相關聯,就像條件隊列和單獨的內部鎖相關聯一樣。每個鎖可以有多個等待集、中斷性選擇、基於時限、公平性選擇等。
public interface Condition{
void await() throws InterruptedException;//相當於wait
boolean await(long time,TimeUnit unit) throws InterruptedException;
long awaitNanos(long nanosTimeout) throws InterruptedException;
void awaitUninterruptibly();
boolean awaitUntil(Date deadline) throws InterruptedException;
void signal();//相當於notify
void signalAll();//相當於notifyall
}
調用與Condition相關聯的Lock的Lock.newCondition方法,可創建一個Condition.
3、有限緩存操作
@ThreadSafe
public class ConditionBoundedBufferT{
protected final Lock lock=new ReentrantLock();
private final Condition notFull=lock.newCondition();
private final Condition notEmpty=lock.newCondition();
@GuardBy(“lock”);
private final T[] items=(T[]) new Object[BUFFER_SIZE];
@GuardBy(“lock”) private int tail,head,count;
public void put(T x) throws InterruptedExceptoin{
lock.lock();
try{
while (count=items.lentgh)
notFull.await();
items[tail]=x;
if (++tail=items.length)
tail=0;
++count;
notEmpty.signal();
}
finally{lock.unlock();
}
}
public T take() throws InterruptedException{
lock.lock();
try{
while (count=items.lentgh)
notEmpty.await();
T x=items[head];
items[head]=null;
if (++head=items.length)
head=0;
–count;
notFull.signal();
return x;
}
finally{lock.unlock();
}
}
}
Java中Lock,tryLock,lockInterruptibly有什麼區別
Java中Lock,tryLock,lockInterruptibly的區別如下:
一、 lock()方法
使用lock()獲取鎖,若獲取成功,標記下是該線程獲取到了鎖(用於鎖重入),然後返回。若獲取失敗,這時跑一個for循環,循環中先將線程阻塞放入等待隊列,當被調用signal()時線程被喚醒,這時進行鎖競爭(因為默認使用的是非公平鎖),如果此時用CAS獲取到了鎖那麼就返回,如果沒獲取到那麼再次放入等待隊列,等待喚醒,如此循環。其間就算外部調用了interrupt(),循環也會繼續走下去。一直到當前線程獲取到了這個鎖,此時才處理interrupt標誌,若有,則執行 Thread.currentThread().interrupt(),結果如何取決於外層的處理。lock()最終執行的方法如下:
[java] view plain copy
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head tryAcquire(arg)) { //如果競爭得到了鎖
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted; //獲取成功返回interrupted標誌
}
// 只修改標誌位,不做其他處理
if (shouldParkAfterFailedAcquire(p, node) strongparkAndCheckInterrupt()/strong)
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
其中parkAndCheckInterrupt()調用了LockSupport.park(),該方法使用Unsafe類將進程阻塞並放入等待隊列,等待喚醒,和await()有點類似。
可以看到循環中檢測到了interrupt標記,但是僅做 interrupted = true 操作,直到獲取到了鎖,才return interrupted,然後處理如下
[java] view plain copy
public final void acquire(int arg) {
if (!tryAcquire(arg) acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt(); // 執行Thread.currentThread().interrupt()
}
二、 lockInterruptibly()方法
和lock()相比,lockInterruptibly()只有略微的修改,for循環過程中,如果檢測到interrupt標誌為true,則立刻拋出InterruptedException異常,這時程序變通過異常直接返回到最外層了,又外層繼續處理,因此使用lockInterruptibly()時必須捕捉異常。lockInterruptibly()最終執行的方法如下:
[java] view plain copy
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return; //獲取成功返回
}
if (shouldParkAfterFailedAcquire(p, node)
parkAndCheckInterrupt())
throw new InterruptedException(); //直接拋出異常
}
} finally {
if (failed)
cancelAcquire(node);
}
}
三、 tryLock()方法
使用tryLock()嘗試獲取鎖,若獲取成功,標記下是該線程獲取到了鎖,然後返回true;若獲取失敗,此時直接返回false,告訴外層沒有獲取到鎖,之後的操作取決於外層,代碼如下:
[java] view plain copy
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc 0) // overflow
throw new Error(“Maximum lock count exceeded”);
setState(nextc);
return true;
}
return false;
}
深入研究 Java Synchronize 和 Lock 的區別與用法
一、synchronized和lock的用法區別
synchronized:在需要同步的對象中加入此控制,synchronized可以加在方法上,也可以加在特定代碼塊中,括弧中表示需要鎖的對象。
lock:需要顯示指定起始位置和終止位置。一般使用ReentrantLock類做為鎖,多個線程中必須要使用一個ReentrantLock類做為對象才能保證鎖的生效。且在加鎖和解鎖處需要通過lock()和unlock()顯示指出。所以一般會在finally塊中寫unlock()以防死鎖。
二、synchronized和lock用途區別
synchronized原語和ReentrantLock在一般情況下沒有什麼區別,但是在非常複雜的同步應用中,請考慮使用ReentrantLock,特別是遇到下面2種需求的時候。
1.某個線程在等待一個鎖的控制權的這段時間需要中斷
2.需要分開處理一些wait-notify,ReentrantLock裡面的Condition應用,能夠控制notify哪個線程
3.具有公平鎖功能,每個到來的線程都將排隊等候
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/236873.html