锁分类参考文章
基本使用
1.继承与实现
public class ReentrantLock implements Lock, java.io.Serializable
Lock 接口
// 如果锁可用就获得锁,如果锁不可用就阻塞直到锁释放
void lock();
// 和lock()方法相似, 但阻塞的线程 可 中 断 , 抛 出java.lang.InterruptedException 异常
void lockInterruptibly() throws InterruptedException;
// 非阻塞获取锁;尝试获取锁,如果成功返回 true
boolean tryLock();
//带有超时时间的获取锁方法
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
// 释放锁
void unlock();
Condition newCondition();
2.ReentrantLock 重入锁
重入锁,表示支持重新进入的锁,也就是说,如果当前线程 t1 通过调用 lock 方法获取了锁之后,再次调用 lock,是不会再阻塞去获取锁的,直接增加重试次数就行了。synchronized 和 ReentrantLock 都是可重入锁。
- 可中断
- 可以设置超时时间
- 可以设置为公平锁
- 支持多个条件变量
基本语法
//获取锁
reetrantLock.lock();
try{
//临界区
}finally{
//释放锁
reentrantLock.unlock();
}
可重入
可重入指一个线程如果首次获取这把锁,他就是这把锁的拥有者,有权再次获取这把锁。如果是不可重入锁,那么第二次获得锁时,自己也会被锁挡住。
可打断
如果用的lock.lockInterruptibly()这个方法上锁的话,别的线程是可以通过interrupt方法打断的。比如:我的a线程正在尝试获取锁,但这个lock已经被b线程拿了,b可以如果执行Interrupt就可以把a线程正在尝试的打断直接获取失败不等待。就是一种防止无限制等待的机制,避免死等,减少死锁的产生。
锁超时
有个lock.tryLock()方法,返回boolean,获取到就返回true,获取不到锁就返回false,这个方法的可以传入两个参数超时时间,第一个参数数字代表时间,第二个是单位。代表他去tryLock()尝试获取锁的时候最多等待的实践,如果是1和秒就是最多尝试等待一秒,还没拿到就返回false。也是一直超时机制,防止死锁。
公平锁
syn就是非公平的,重量级的monitor的堵塞队列就是非公平的。
ReentrantLock默认是不公平,但是我们可以通过构造方法改成公平的,传的是boolean值
条件变量
syn不满足条件的线程都在一个休息室
而ReentranLock支持多休息室,唤醒的时候也是按照休息室来唤醒
使用流程:
- await进行等待(前需要获得锁)
- await执行后,会释放锁,进入conditionObject等待
- await的线程被唤醒(或打断或超时)去重新竞争lock锁
- 竞争lock锁成功后,从await后继续执行
在new完ReentranLock之后可以用newCondition()方法创建休息室,然后就可以用new出来的condition调用await方法进入休息室等待,唤醒的话是signal()方法
3.可调用的方法
4.构造
public ReentrantLock() {
sync = new NonfairSync();
}
//fair true 创建公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
5.获取锁
//获取锁,获取不到,会等待知道获取
public void lock() {
sync.lock();
}
//可被其它线程打断的锁
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
//直接获取锁,成功则返回true 失败返回fasle
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
//指定时间范围获取锁,传入超时时间和单位
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
6.释放锁
public void unlock() {
sync.release(1);
}
7.查看锁的状态
//查询此锁是否由任何线程持有。此方法设计用于监视系统状态,而不是用于同步控制。
public boolean isLocked() {
return sync.isLocked();
}
8.是否是公平锁
public final boolean isFair() {
return sync instanceof FairSync;
}
9.tostring
//返回类型名@hashcode值,是否被锁,锁着的时候返回线程名
//java.util.concurrent.locks.ReentrantLock@30ee82d7[Locked by thread Thread-0]
public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
测试使用
public class Test5 {
static ReentrantLock reentrantLock = new ReentrantLock();
static Test5 test5;
static Thread thread1;
public static int a = 5;
public void test() {
System.err.println("hashCode"+reentrantLock.hashCode());
boolean tryLock;
try {
tryLock = reentrantLock.tryLock(5, TimeUnit.SECONDS);
System.err.println("getHoldCount:"+reentrantLock.hasQueuedThreads());
/*Condition newCondition = reentrantLock.newCondition();
newCondition.awaitUninterruptibly();*/
System.out.println("线程"+Thread.currentThread().getName()+":开始调用Test5");
System.out.println("线程"+Thread.currentThread().getName()+":拿到锁"+reentrantLock.isLocked());
if(!tryLock)
return;
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
try {
for (int i = 0; i < 20; i++) {
Thread.sleep(10);
a++;
System.out.println("线程"+Thread.currentThread().getName()+":"+ a);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
System.out.println("线程"+Thread.currentThread().getName()+":释放锁");
reentrantLock.unlock();
}
}
public static void main(String[] args) {
thread1 = new Thread() {
public void run() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
test5 = new Test5();
test5.test();
};
};
thread1.start();
new Thread() {
public void run() {
test5 = new Test5();
test5.test();
};
}.start();
new Thread() {
public void run() {
try {
Thread.sleep(60);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.err.println("getHoldCount:"+reentrantLock.getHoldCount());
};
}.start();
}
}
源码实现
1.Sync
abstract static class Sync extends AbstractQueuedSynchronizer
abstract void lock();
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;
}
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
// Methods relayed from outer class
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked() {
return getState() != 0;
}
/**
* Reconstitutes the instance from a stream (that is, deserializes it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
2.NonfairSync
static final class NonfairSync extends Sync{
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);//AbstractQueuedSynchronizer 的方法
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}}
3.FairSync
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
下篇文章继续学习