1.ReentrantLock
在Java多線(xiàn)程中,可以使用synchronized關(guān)鍵字來(lái)實(shí)現(xiàn)線(xiàn)程之間的同步互斥枕荞。但是在Java 1.5中新增了ReentrantLock類(lèi)也能達(dá)到同樣的效果斥季。并且擴(kuò)展了許多功能锦溪。比synchronized更加靈活。
代碼演示
新建業(yè)務(wù)類(lèi)
public class Business {
private Lock lock = new ReentrantLock();
public void print() {
//lock.lock();
for (int i = 0; i < 5; i++) {
System.out.println(String.format("%s:%d", Thread.currentThread().getName(), i));
}
//lock.unlock();
}
}
- 新建線(xiàn)程A
public class ThreadA extends Thread {
private Business business;
public ThreadA(Business business) {
super();
this.business = business;
}
@Override
public void run() {
business.print();
}
}
- 新建線(xiàn)程B
public class ThreadB extends Thread {
private Business business;
public ThreadB(Business business){
this.business=business;
}
@Override
public void run() {
business.print();
}
}
- Client
public class Client {
public static void main(String[] args) {
Business business = new Business();
ThreadA a = new ThreadA(business);
ThreadB b = new ThreadB(business);
a.start();
b.start();
}
}
- 沒(méi)加鎖的結(jié)果
線(xiàn)程B:0
線(xiàn)程B:1
線(xiàn)程B:2
線(xiàn)程B:3
線(xiàn)程B:4
線(xiàn)程A:0
線(xiàn)程A:1
線(xiàn)程A:2
線(xiàn)程A:3
線(xiàn)程A:4
- 加鎖后的結(jié)果
線(xiàn)程B:0
線(xiàn)程B:1
線(xiàn)程B:2
線(xiàn)程B:3
線(xiàn)程B:4
線(xiàn)程A:0
線(xiàn)程A:1
線(xiàn)程A:2
線(xiàn)程A:3
線(xiàn)程A:4
由此可看出综苔,ReentrantLock實(shí)現(xiàn)了synchronized的同步的功能惩系。lock.lock()是獲取鎖。lock.unlock()是釋放鎖如筛。
1.1結(jié)合Condition實(shí)現(xiàn)wait與notify功能
關(guān)鍵字synchronized與wait及notify結(jié)合堡牡,可以實(shí)現(xiàn)等待、通知模式杨刨。而ReentrantLock與Condition結(jié)合也可以實(shí)現(xiàn)同樣的功能晤柄。
代碼演示
新建業(yè)務(wù)類(lèi)
public class Business {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private int num;
public void print() {
try {
lock.lock();
for (int i = 0; i < 5; i++) {
System.out.println(String.format("%s:%d", Thread.currentThread().getName(), i));
num = i;
if (i == 2){
condition.await();
System.out.println("接受到信號(hào),執(zhí)行完畢");
}
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
lock.unlock();
}
}
public void notifyPrint() {
lock.lock();
if (num == 2)
condition.signal();
lock.unlock();
}
}
- 新建線(xiàn)程A
public class ThreadA extends Thread {
private Business business;
public ThreadA(Business business) {
super();
this.business = business;
}
@Override
public void run() {
business.print();
}
}
- 新建線(xiàn)程B
public class ThreadB extends Thread {
private Business business;
public ThreadB(Business business) {
this.business = business;
}
@Override
public void run() {
business.notifyPrint();
}
}
- Client
public class Client {
public static void main(String[] args) throws InterruptedException {
Business business = new Business();
ThreadA a = new ThreadA(business);
a.setName("線(xiàn)程A");
ThreadB b = new ThreadB(business);
b.setName("線(xiàn)程B");
a.start();
Thread.sleep(2000);
b.start();
}
}
- 結(jié)果
Connected to the target VM, address: '127.0.0.1:62623', transport: 'socket'
線(xiàn)程A:0
線(xiàn)程A:1
線(xiàn)程A:2
Disconnected from the target VM, address: '127.0.0.1:62623', transport: 'socket'
接受到信號(hào)妖胀,執(zhí)行完畢
線(xiàn)程A:3
線(xiàn)程A:4
下面圖標(biāo)表示Object里面的類(lèi)的方法與Condition類(lèi)的方法對(duì)比
Object | Condition |
---|---|
wait() | await() |
wait(long timeout) | await(long time, TimeUnit unit) |
notify() | signal() |
notifyAll() | signalAll() |
1.2 Condition的部分喚醒
在服務(wù)類(lèi)中創(chuàng)建多個(gè)Condition實(shí)例芥颈。進(jìn)行對(duì)其分組操作。
private Condition condition = lock.newCondition();
private Condition condition2 = lock.newCondition();
1.3公平鎖與非公平鎖
公平鎖:線(xiàn)程獲取鎖的順序是按照線(xiàn)程加鎖的順序來(lái)分配的赚抡。即先進(jìn)先出的順序(FIFO)爬坑。
非公平鎖:獲取鎖的搶占機(jī)制,是隨機(jī)獲得鎖的涂臣。
- ReentrantLock的構(gòu)造函數(shù)
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
傳入true為公平鎖妇垢,傳入false為非公平鎖。
1.4ReentrantLock及Condition其他重要方法
- 1.getHoldCount
查詢(xún)當(dāng)前線(xiàn)程保持鎖定的個(gè)數(shù),也就是調(diào)用lock()的次數(shù)
public int getHoldCount() {
return sync.getHoldCount();
}
- 2.getQueueLength
計(jì)算正等待獲取此鎖定的線(xiàn)程數(shù)闯估。比如一個(gè)線(xiàn)程在鎖內(nèi)休眠灼舍,其他9個(gè)線(xiàn)程正在等待,那么調(diào)用此方法返回9涨薪。
public final int getQueueLength() {
return sync.getQueueLength();
}
- 3.getWaitQueueLength
返回給定條件的Condition相關(guān)的等待此鎖的線(xiàn)程數(shù)骑素。
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
- 4.hasQueuedThread
查詢(xún)指定的線(xiàn)程是否正在等待獲取此鎖
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
- 5.hasQueuedThreads
查詢(xún)是否有線(xiàn)程正在等待獲取此鎖
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
- 6.hasWaiters
根據(jù)Condition條件去查詢(xún)是否有線(xiàn)程正在等待獲取此鎖
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
- 7.isFair
判斷是不是公平鎖
public final boolean isFair() {
return sync instanceof FairSync;
}
- 8.isHeldByCurrentThread
查詢(xún)當(dāng)前是否保持鎖定
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
- 9.isLocked
判斷當(dāng)前鎖是否由任意線(xiàn)程鎖定
public boolean isLocked() {
return sync.isLocked();
}
- 10.lockInterruptibly
如果當(dāng)前線(xiàn)程未被中斷,則獲取獲取鎖定刚夺,(相當(dāng)于lock())如果已經(jīng)中斷則拋出異常
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
- 11.tryLock
當(dāng)鎖沒(méi)有被其他線(xiàn)程占用献丑,則獲取鎖定。
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
- 12.tryLock(long timeout, TimeUnit unit)
在給定的時(shí)間內(nèi)侠姑,鎖沒(méi)有被其他線(xiàn)程占用创橄,則獲取鎖
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
- 13.awaitUninterruptibly
線(xiàn)程在等待的時(shí)候,線(xiàn)程若主動(dòng)拋出異常莽红,則相對(duì)應(yīng)的程序也不會(huì)拋出異常妥畏。
public final void awaitUninterruptibly() {
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean interrupted = false;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if (Thread.interrupted())
interrupted = true;
}
if (acquireQueued(node, savedState) || interrupted)
selfInterrupt();
}
- 14.awaitUntil
某線(xiàn)程在指定的時(shí)間內(nèi)處于等待狀態(tài),超過(guò)時(shí)間安吁,自動(dòng)運(yùn)行線(xiàn)程醉蚁。
public final boolean awaitUntil(Date deadline)
throws InterruptedException {
long abstime = deadline.getTime();
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (System.currentTimeMillis() > abstime) {
timedout = transferAfterCancelledWait(node);
break;
}
LockSupport.parkUntil(this, abstime);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
2.ReentrantReadWriteLock
ReentrantLock具有完全互斥排他的效果,即同一時(shí)間只有一個(gè)線(xiàn)程在執(zhí)行ReentrantLock.Lock()方法后面的任務(wù)鬼店。
這樣雖然保證了實(shí)例變量的線(xiàn)程安全性网棍,但是效率卻是低下的。這時(shí)候就誕生了讀寫(xiě)鎖ReentrantReadWriteLock妇智。
讀寫(xiě)鎖有兩個(gè)鎖:
- 1.共享鎖:讀操作相關(guān)的鎖
- 2.排他鎖:寫(xiě)操作相關(guān)的鎖
private ReentrantReadWriteLock lock1 = new ReentrantReadWriteLock();
lock1.writeLock().lock();
lock1.writeLock().unlock();
lock1.readLock().lock();
lock1.readLock().unlock();
同一個(gè)類(lèi)中滥玷,有兩個(gè)及兩個(gè)以上的方法。一個(gè)使用讀鎖巍棱,一個(gè)使用寫(xiě)鎖罗捎。那么它們是互斥的。只有所有的方法是讀鎖拉盾,才是不相互干擾,不排斥的豁状。