Java多线程学习四 Lock的使用
2019-04-18 本文已影响0人
殷俊杰
一、 配合Condition使用
Condition的await()方法相当于Object的wait()方法,signal相当于notify,signalAll相当于notifyAll,且它们都必须在持有锁的时候才能调用。
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时间为:"+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();
}
}
如果在调用Condition的await方法没有持有锁的话会报异常,和调用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)
二、使用多个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时间为:"+System.currentTimeMillis());
conditionA.signal();
}finally {
lock.unlock();
}
}
public void signalB(){
try {
lock.lock();
System.out.println("signalB时间为:"+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先进先出顺序。
非公平锁:获取锁是随机的,由各线程抢夺,先来的不一定闲的,这个方式可能造成某些线程一直拿不到锁。
创建公平锁:Lock lock=new ReentrantLock(true)
非公平锁:Lock lock=new ReentrantLock(false)
四、Lock常用方法
- int getHoldCount()
查询当前线程保持次锁定的个数,也就是调用lock()方法的次数 - int getQueueLength()
返回正等待获取此锁的线程的估计数 - int getWaitQueueLength(Condition condition)
返回等待与此锁相关的给定条件Condition的线程估计数 - boolean hasQueuedThread(Thread thread)
查询指定的线程是否正在等待获取此锁 - boolean hasQueuedThreads()
查询是否有线程正在等待获取此锁 - boolean hasWaiters(Condition condition)
查询是否有现成正在等待与此锁有关的condition条件 - boolean isFair()
判断是不是公平锁 - boolean isHeldByCurrentThread()
查询当前线程是否保持此锁定 - boolean isLocked()
查询此锁是否由任意线程保持 - void lockInterruptibly()
如果当前线程未被中断,则获取锁定,如果已经被中断则出现异常。 - boolean tryLock()
成功获取了锁的情况下才会返回true,如果别的线程当前正持有锁,则会立即返回false - boolean tryLock(long timeOut,TimeUnit unit)
如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。
...省略好几个方法,去看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也是可重入的