1.可重入鎖Lock
鎖主要是為了保護臨界區資源,防止由于并發執行而引起的數據異常。而synchronized關鍵字就是一種最簡單的控制方法。經過jdk1.6對synchronized的優化,Lock和synchronized的性能相差并不多。 那么為什么還需要Lock,這當然有它的用處, 先看一個示例,鎖的普通情況的使用:
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo implements Runnable {static int i =
0 ; ReentrantLock lock =
new ReentrantLock();
@Override public void run () {
for (
int j =
0 ; j <
10000 ; j++) {lock.lock();
try {++i;}
finally {lock.unlock(); }}}
public static void main (String[] args) {ReentrantLockDemo lockDemo =
new ReentrantLockDemo();Thread t1 =
new Thread(lockDemo);Thread t2 =
new Thread(lockDemo);t1.start();t2.start();
try {t1.join(); t2.join();}
catch (InterruptedException e) {e.printStackTrace();}System.out.println(i);}
}
Lock額外提供可幾個以下的功能: 1)可重入 之所以把Lock稱作可重入鎖,是因為這把鎖是可以反復進入的,當然這里反復進入僅僅局限于一個線程。上述代碼的加鎖部分,也可以加兩把鎖,如下:
lock .lock ();
lock .lock ();
try {++i;
} finally {
lock .unlock();lock .unlock();
}
注意:如果同一個線程多次獲得鎖,那么也必須釋放相同次數的鎖;如果釋放次數多,那么會得到一個java.lang.IllegalMonitorStateException異常;如果釋放次數少,那么其它線程將不能進入臨界區。 2)中斷響應 對于synchronized來說,如果一個線程在等待鎖,那么結果只有兩種情況,要么它獲得鎖繼續執行,要么就等待。而使用重入鎖,那么鎖可以被中斷,即在等待過程中,程序可以根據需要取消對鎖的請求。
import java.util.concurrent.locks.ReentrantLock;
public class IntLock implements Runnable {ReentrantLock lock1 =
new ReentrantLock();ReentrantLock lock2 =
new ReentrantLock();
int lock;
public IntLock (
int lock) {
this .lock = lock;}
@Override public void run () {
try {
if (lock ==
1 ){lock1.lockInterruptibly(); Thread.sleep(
500 );lock2.lockInterruptibly();System.out.println(Thread.currentThread().getId() +
": 完成" );}
else {lock2.lockInterruptibly();Thread.sleep(
500 );lock1.lockInterruptibly();System.out.println(Thread.currentThread().getId() +
": 完成" );}}
catch (InterruptedException e) {e.printStackTrace();}
finally {
if (lock1.isHeldByCurrentThread()) lock1.unlock();
if (lock2.isHeldByCurrentThread())lock2.unlock();System.out.println(Thread.currentThread().getId() +
": 線程退出!" );}}
public static void main (String[] args) {IntLock intLock1 =
new IntLock(
1 );IntLock intLock2 =
new IntLock(
2 );Thread t1 =
new Thread(intLock1);Thread t2 =
new Thread(intLock2);t1.start();t2.start();t1.interrupt(); }
}
3)鎖申請等待限時
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class TryLockDemo implements Runnable {ReentrantLock lock =
new ReentrantLock();
@Override public void run () {
try {
if (lock.tryLock(
5 , TimeUnit.SECONDS)){ Thread.sleep(
6000 );System.out.println(Thread.currentThread().getId() +
"complete!" );}
else {System.out.println(Thread.currentThread().getId() +
"get lock failed" );}}
catch (InterruptedException e) {e.printStackTrace();}
finally {
if (lock.isHeldByCurrentThread()) lock.unlock();}}
public static void main (String[] args) {TryLockDemo tryLockDemo =
new TryLockDemo();Thread t1 =
new Thread(tryLockDemo);Thread t2 =
new Thread(tryLockDemo);t1.start();t2.start();}
}
tryLock()也可以不帶參數直接運行,在這種情況下,如果申請不成功,則直接返回false,不會等待。 4)總結 public void lock():獲得鎖,如果鎖已經被占用,則等待; public void lockInterruptibly():獲得鎖,但優先響應中斷; public boolean tryLock():嘗試獲得鎖,如果成功返回true,繼續執行;如果失敗,返回false,不等待; boolean tryLock(long timeout, TimeUnit unit):鎖申請等待限時; public void unlock():釋放鎖;
2.線程通信 (Condition)
Condition提供了一下幾個方法:
void await()
throws InterruptedException;
void awaitUninterruptibly();
boolean await(
long time, TimeUnit unit)
throws InterruptedException;
void signal();
void signalAll();
其和Object.wait()、Object.notify()方法作用類似; await()方法使當前線程等待,同時釋放鎖;在其它線程中調用signal()方法或者signalAll()方法,線程會被喚醒,獲得鎖繼續執行。當線程被中斷時,也能跳出等待; awaitUninterruptibly()作用和await()方法類似,但它不響應中斷; signal()方法用于喚醒線程。 示例如下:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionDemo implements Runnable {private static Lock lock =
new ReentrantLock();
private static Condition condition = lock.newCondition();
@Override public void run () {
try {lock.lock();condition.await();System.out.println(
"執行完畢" );}
catch (InterruptedException e) {e.printStackTrace();}
finally {lock.unlock();}}
public static void main (String[] args)
throws InterruptedException {ConditionDemo conditionDemo =
new ConditionDemo();Thread t1 =
new Thread(conditionDemo);t1.start();Thread.sleep(
2000 );lock.lock(); condition.signal();lock.unlock(); }
}
一旦線程被喚醒,它會重新嘗試獲得與其綁定的重入鎖,如果成功獲取就繼續執行。
總結
以上是生活随笔 為你收集整理的Java的可重入锁 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。