Java—多线程7 Lock1
首先synchronize(this){}是自动加解锁
JDK1.5后新增了一个guc开发包 java.util.concurrent.locks,体统了与内建锁不同的实现多线程线程共享访问机制。失去了内建锁隐式的加锁与解锁过程。增加了可中断的获取锁,以及超时获取锁以及共享锁等内建锁不具备的特性。
##lock锁的标准使用形式
1.显示的上锁和解锁过程
Lock lock=new Lock();
try{
lock.lock();
//同步快
}finally{
lock.unlock();
}
lock接口API
lock接口API | 解释 |
---|---|
void lock() | 获取锁 |
void lockInterruptibly()thrwos InterruptedException | 获取锁的过程可以响应中断 |
boolean tryLock() | 获取锁返回true,反之返回false可以响应中断 |
boolean tryLock(long time,TimeUnit unit) | 在3的基础上增加超时等待机制,规定时间内未获取到锁,线程直接返回(Lock独有) |
void unLock | 解锁 |
在Lock接口实现了几种方法:
ReadWriterLock
ReentrantLock
ReentrantReadWriterLock
AbstractQueuedSynchronizer(AQS)同步器
1、同步器是用来构建锁与其他同步组件的基础框架。他的实现主要依赖一个int成员变量表示同步状态以及通过一个FIFO队列构成同步队列。
要使用AQS,推荐使用静态内部类继承AQS,覆写AQS中的protected用来改变同步状态的方法,其他方法主要是实现排队与阻塞机制。状态更新使用getState() setState() compareAndSetState()。
自定义锁
class MyLock implements Lock{
private Sync sync=new Sync();
static class Sync extends AbstractQueuedSynchronizer{
//默认的同步状态为1
@Override
protected boolean tryAcquire(int arg) {
if(arg!=1){
throw new RuntimeException("同步状态为1");
}
if(compareAndSetState(0,1)){
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
@Override
protected boolean tryRelease(int arg) {
if(getState()==0){
throw new IllegalMonitorStateException();
}
setExclusiveOwnerThread(null);
setState(0);
return true;
}
@Override
protected boolean isHeldExclusively() {
return getState()==1;
}
}
@Override
public void lock() {
sync.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1,time);
}
@Override
public void unlock() {
sync.tryRelease(1);
}
@Override
public Condition newCondition() {
return null;
}
}
class MyThread implements Runnable{
MyLock myLock=new MyLock();
@Override
public void run() {
try {
myLock.lock();
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
myLock.unlock();
}
}
}
public class Test {
public static void main(String[] args) {
MyThread myThread=new MyThread();
for(int i=0;i<10;i++){
new Thread(myThread).start();
}
}
}
lock面向使用者,定义了使用者与锁交互的接口,隐藏了实现细节;
AQS面向锁的实现者,简化了锁的实现方法,屏蔽了同步状态管理、线程排队、线程等待与唤醒等底层操作。
AQS的模板方法
Lock体系的实现使用了AQS中的模板方法来实现同步语义。
独占锁:
AQS方法 | 解释 |
---|---|
void aquire(int arg)//模板方法 | 独占式获取同步状态,如果获取失败则将当前线程插入同步队列进行等待 |
void acquireInterruptibly(int arg) | 在一的基础上增加响应中断 |
boolean tryAquireNanos(int arg,long nanosTimeOut) | 在2的基础上增加超时等待,在规定时间内未获取到同步状态返回flase |
boolean tryAcquire(int arg) | 获取状态成功返回true,否则返回false |
boolean release() | 释放同步状态,该方法唤醒在同步队列中的下一个结点 |
共享锁:
AQS方法 | 解释 |
---|---|
void aquireShared(int arg) | 共享式获取同步状态,和独占锁不同在于同一时刻有多个线程获取同步状态。 |
void aquireSharedInterruptly(int arg) | 增加了响应中断功能 |
boolean tryAquireShareNanos(int arg,long nanosTimeout) | 在2的基础上增加了超时等到功能 |
boolean releaseShared(int arg) | 共享状态释放锁 |
##同步队列
在AQS内部有一个静态内部类Node,这是同步队列中每个具体的结点。结点有如下属性:
int waitStatus:结点状态
AQS中的同步队列是一个带有头尾结点的双向链表,结点组成为
Node prev;同步队列中的前驱结点
Node next;同步队列中的后继结点
Thread thread:当前节点包装的线程对象
Node nextWaiter:等待队列中下一个结点****
结点状态值:
//初始状态
static final int INITIAL=0;
/** waitStatus value to indicate thread has cancelled */
//当前节点从同步队列中取消
static final int CANCELLED = 1;
/** waitStatus value to indicate successor's thread needs unparking */
//后继结点处于阻塞状态(Wait)状态。
static final int SIGNAL = -1;
/** waitStatus value to indicate thread is waiting on condition */
//结点处于等待队列中。当其他线程会Condition调用sinal
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
static final int PROPAGATE = -3;
将线程封装为Node节点后进行入队和出队处理。
头结点:方便对第一个线程进行插入和删除。
1.入队 获取锁失败;出队,获取锁成功。