一、 配合Condition使用
Condition的await()方法相當(dāng)于Object的wait()方法,signal相當(dāng)于notify,signalAll相當(dāng)于notifyAll,且它們都必須在持有鎖的時(shí)候才能調(diào)用。
public class MyService {
private Lock lock=new ReentrantLock();
private Condition condition=lock.newCondition();
public void await(){
try {
System.out.println("wait begin"+System.currentTimeMillis());
lock.lock();
condition.await();
System.out.println("wait end"+System.currentTimeMillis());
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void signal(){
try {
lock.lock();
System.out.println("signal時(shí)間為:"+System.currentTimeMillis());
condition.signal();
}finally {
lock.unlock();
}
}
}
public class MyThread extends Thread {
private MyService myService;
public MyThread(MyService myService) {
this.myService = myService;
}
@Override
public void run() {
myService.await();
}
}
public class TestMain {
public static void main(String[] args) throws InterruptedException {
MyService myService=new MyService();
MyThread myThread=new MyThread(myService);
myThread.start();
Thread.sleep(3000);
myService.signal();
}
}
如果在調(diào)用Condition的await方法沒有持有鎖的話會(huì)報(bào)異常,和調(diào)用Object的wait方法一樣
public void await(){
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.fullyRelease(AbstractQueuedSynchronizer.java:1723)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2036)
at com.yjj.chapter04.test02_condition.MyService.await(MyService.java:29)
at com.yjj.chapter04.test02_condition.MyThread.run(MyThread.java:18)
二、使用多個(gè)Condition通知部分線程
package com.yjj.chapter04.test03_condition2;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Description:
* @Author: YinJunjie
* @CreateDate: 2018/9/27 15:45
* @Version: 1.0
*/
public class MyService {
private Lock lock=new ReentrantLock();
private Condition conditionA=lock.newCondition();
private Condition conditionB=lock.newCondition();
public void awaitA(){
try {
System.out.println("waitA begin"+System.currentTimeMillis());
lock.lock();
conditionA.await();
System.out.println("waitA end"+System.currentTimeMillis());
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void awaitB(){
try {
System.out.println("waitB begin"+System.currentTimeMillis());
lock.lock();
conditionB.await();
System.out.println("waitB end"+System.currentTimeMillis());
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void signalA(){
try {
lock.lock();
System.out.println("signalA時(shí)間為:"+System.currentTimeMillis());
conditionA.signal();
}finally {
lock.unlock();
}
}
public void signalB(){
try {
lock.lock();
System.out.println("signalB時(shí)間為:"+System.currentTimeMillis());
conditionB.signal();
}finally {
lock.unlock();
}
}
}
public class MyThreadA extends Thread {
private MyService myService;
public MyThreadA(MyService myService) {
this.myService = myService;
}
@Override
public void run() {
myService.awaitA();
}
}
public class MyThreadB extends Thread {
private MyService myService;
public MyThreadB(MyService myService) {
this.myService = myService;
}
@Override
public void run() {
myService.awaitB();
}
}
public static void main(String[] args) throws InterruptedException {
MyService myService=new MyService();
MyThreadA myThreadA =new MyThreadA(myService);
MyThreadB myThreadB =new MyThreadB(myService);
myThreadB.start();
myThreadA.start();
Thread.sleep(3000);
myService.signalA();
Thread.sleep(3000);
myService.signalB();
}
三、公平鎖與非公平鎖
公平鎖:線程獲取說的順序是按照線程加鎖的順序來分配的,即先來先得FIFO先進(jìn)先出順序。
非公平鎖:獲取鎖是隨機(jī)的,由各線程搶奪,先來的不一定閑的,這個(gè)方式可能造成某些線程一直拿不到鎖。
創(chuàng)建公平鎖:Lock lock=new ReentrantLock(true)
非公平鎖:Lock lock=new ReentrantLock(false)
四、Lock常用方法
- int getHoldCount()
查詢當(dāng)前線程保持次鎖定的個(gè)數(shù),也就是調(diào)用lock()方法的次數(shù) - int getQueueLength()
返回正等待獲取此鎖的線程的估計(jì)數(shù) - int getWaitQueueLength(Condition condition)
返回等待與此鎖相關(guān)的給定條件Condition的線程估計(jì)數(shù) - boolean hasQueuedThread(Thread thread)
查詢指定的線程是否正在等待獲取此鎖 - boolean hasQueuedThreads()
查詢是否有線程正在等待獲取此鎖 - boolean hasWaiters(Condition condition)
查詢是否有現(xiàn)成正在等待與此鎖有關(guān)的condition條件 - boolean isFair()
判斷是不是公平鎖 - boolean isHeldByCurrentThread()
查詢當(dāng)前線程是否保持此鎖定 - boolean isLocked()
查詢此鎖是否由任意線程保持 - void lockInterruptibly()
如果當(dāng)前線程未被中斷,則獲取鎖定,如果已經(jīng)被中斷則出現(xiàn)異常。 - boolean tryLock()
成功獲取了鎖的情況下才會(huì)返回true,如果別的線程當(dāng)前正持有鎖,則會(huì)立即返回false - boolean tryLock(long timeOut,TimeUnit unit)
如果鎖在給定等待時(shí)間內(nèi)沒有被另一個(gè)線程保持,且當(dāng)前線程未被中斷,則獲取該鎖。
...省略好幾個(gè)方法,去看jdk api吧
五、讀寫鎖
public class MyService {
private ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
public void read(){
try {
lock.readLock().lock();
System.out.println(Thread.currentThread().getName()+"讀啊讀");
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.readLock().unlock();
System.out.println(Thread.currentThread().getName()+"讀完了");
}
}
public void write(){
try {
lock.writeLock().lock();
System.out.println(Thread.currentThread().getName()+"寫啊寫");
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.writeLock().unlock();
System.out.println(Thread.currentThread().getName()+"寫完了");
}
}
}
public class ReadThread extends Thread {
private MyService myService;
public ReadThread(MyService myService) {
this.myService = myService;
}
@Override
public void run() {
myService.read();
}
}
public class WriteThread extends Thread {
private MyService myService;
public WriteThread(MyService myService) {
this.myService = myService;
}
@Override
public void run() {
myService.write();
}
}
讀讀不互斥
MyService myService = new MyService();
ReadThread readThread1 = new ReadThread(myService);
ReadThread readThread2 = new ReadThread(myService);
readThread1.setName("read1");
readThread2.setName("read2");
readThread1.start();
readThread2.start();
read1讀啊讀
read2讀啊讀
read1讀完了
read2讀完了
讀寫互斥
MyService myService=new MyService();
ReadThread readThread=new ReadThread(myService);
WriteThread writeThread=new WriteThread(myService);
readThread.setName("read");
writeThread.setName("write");
readThread.start();
writeThread.start();
read讀啊讀
read讀完了
write寫啊寫
write寫完了
寫寫互斥 略
注意:
ReentrantLock也是可重入的