文章目录
java.util.concurrent包结构
其中包含了两个子包:automic和lock,阻塞队列,executors这些都是juc中的精华。这些类的实现主要依赖于volatile以及CAS
lock简介
锁是用来控制多个线程访问共享资源的方式,java SE5都是靠synchronized实现锁功能的,它拥有很多优点,比如锁获取和释放的可操作性,可中断的获取锁,超时获取锁等其他同步特性
转移:synchronized同步块执行完成或者遇到异常时,锁是会自动释放的,但是lock必须显示释放锁
lock的简单使用
Lock lock=new RentrantLock();
lock.lock();
try{
....
}finally{
lock.unlock();
}
trylock的简单使用
尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false
Lock lock=new RentrantLock();
if (lock.tryLock()) {
try {
// manipulate protected state
} finally {
lock.unlock();
}
} else {
// perform alternative actions
}}
lock定义的方法
- void lock(); //获取锁,就是获取资源
- void unlock(); //释放锁,释放资源给其他线程用
- void lockInterruptibly(); // 可响应中断的获取锁
- boolean tryLock(); //非阻塞式的获取锁
- boolean tryLock(long time, TimeUnit unit) // 在超时时间内或者未中断的情况下获取锁
- Condition newCondition(); //获取与lock锁绑定的等待通知组件
ReentrantLock的实现
基本上所有的方法都是调用了其静态内部类的Sync的方法,而Sunc继承了AbstractQueuedSunchronizer(AQS)
AQS简介
同步器是用来构建锁和其他同步组件的基础框架,它依赖同步状态和一个同步队列,子类必须重写AQS的几个改变状态的方法,其他方法主要实现了排队和阻塞机制
- 锁是面向使用者,定义了使用者与锁交互的接口
- 同步器面向锁的实现者,简化了锁得实现方式,屏蔽了同步状态的管理,线程的排队,等待和唤醒等底层操作。
AQS使用模板方法实现设计模式
模板方法:同步器将一些方法开放给子类重写,而同步器提供的模板方法又会重新调用子类重写的方法
AQS需要重写的方法
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
ReentrantLock重写
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
AQS中的模板方法acquire()
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
重写AQS经验总结
- 同步组件的实现依赖同步器,使用AQS的方式被推介定义 继承AQS的静态内部类
- AQS采用模板方法设计,AQS的protected方法需要子类重写,当调用模板方法时就可以调用被重写方法
- AQS负责同步状态的管理,线程的排队,等待唤醒等底层操作,而自定义同步组件主要专注于 实现同步语义
- 重写AQS时,使用AQS提供的getState().setState(),compareAndSetState()修改同步状态
AQS可重写的方法
- boolean tryAcquire(int arg)
独占式的获取同步状态,需要查询当前状态并判断是否符合预期,然后再通过CAS设置同步状态 - boolean tryRelease(int arg) 独占式的释放同步状态
———————————————————————————————— - int tryAcquireShared(int arg) 共享式的获取同步状态,返回>=0表示获取成功
- boolean tryReleaseShared(int arg)共享式的释放同步状态
- boolean isHeldExclusively() 当前同步器是否被当前线程所独占
实现同步组件时AQS提供的模板方法
- 独占式获取与释放同步状态
- 共享式获取与释放同步状态
- 查询同步队列中等待线程的情况
- void acquire(int arg) 独占式的获取同步状态,若当前线程获取同步状态成功则返回,否则将进入同步队列等待
- boolean release(int arg) 独占式的释放同步状态,释放同步状态后,将同步队列中第一个节点包含的线程唤醒
——————————————————————————————————— - void acquireShared(int arg) 共享式的获取同步状态,同一时刻会有多个线程获取到同步状态
- boolean release(int arg) 共享式的释放同步状态
——————————————————————————————————— - void acquireInterruptibly(int arg) 若当前线程被中断,则抛出异常
- void acquireSharedInterruptibly(int arg) 若当前线程被中断,则抛出异常
实现一个同步组件
class Mutex implements Lock, java.io.Serializable {
// Our internal helper class
// 继承AQS的静态内存类
// 重写方法
private static class Sync extends AbstractQueuedSynchronizer {
// Reports whether in locked state
protected boolean isHeldExclusively() {
return getState() == 1;
}
// Acquires the lock if state is zero
public boolean tryAcquire(int acquires) {
assert acquires == 1; // Otherwise unused
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// Releases the lock by setting state to zero
protected boolean tryRelease(int releases) {
assert releases == 1; // Otherwise unused
if (getState() == 0) throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
// Provides a Condition
Condition newCondition() {
return new ConditionObject();
}
// Deserializes properly
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
// The sync object does all the hard work. We just forward to it.
private final Sync sync = new Sync();
//使用同步器的模板方法实现自己的同步语义
public void lock() {
sync.acquire(1);
}
public boolean tryLock() {
return sync.tryAcquire(1);
}
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
public boolean isLocked() {
return sync.isHeldExclusively();
}
public boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
同步组件实现者角度:告诉AQS怎么判断当前同步状态是否成功获取or成功释放
AQS角度:需要同步组件返回true和false,然后对不同的结果做不同处理