Lock API
Locks包 类层次结构
Lock 接口方法
Condition的使用来实现简单的BlockingQuen
线程虚假唤醒:是一个表象,即在多处理器的系统下发出wait的程序有可 能在没有notify唤醒的情形下苏醒继续执行
https://www.zhihu.com/question/50892224
public class BlockingQueue_Demo {
public static void main(String[] args) throws InterruptedException {
KaneBlockingQueue kaneBlockingQueue = new KaneBlockingQueue(6);
new Thread(){
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
kaneBlockingQueue.put("x"+i);
}
}
}.start();
Thread.sleep(1000L);
System.out.println("开始取元素");
for (int i = 0; i <10 ; i++) {
kaneBlockingQueue.take();
Thread.sleep(2000);
}
}
}
class KaneBlockingQueue{
List<Object> list = new ArrayList<>();
private Lock lock = new ReentrantLock();
private Condition putCondition = lock.newCondition(); //condition可以有多个,针对不同的操作放入不同condition,相当于等待队列
private Condition takeCondition = lock.newCondition();
private int length;
public KaneBlockingQueue(int length){
this.length =length;
}
public void put(Object obj){
lock.lock(); //思考一个读一个写,为什么要加锁呢?
try{
while (true) {//防止线程被虚假唤醒 虚假唤醒(spurious wakeup)是一个表象,即在多处理器的系统下发出wait的程序有可能在没有notify唤醒的情形下苏醒继续执行
if (list.size() < length) { //我们集合的长度不能超过规定的长度,才能向里面放东西
list.add(obj);
System.out.println("队列中放入元素:"+obj);
takeCondition.signal();
return;
} else { //如果放不进去,就该阻塞. --利用condition实现
putCondition.await();//挂起
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public Object take(){
lock.lock();
try{
while (true) {
if (list.size() > 0) {
Object obj = list.remove(0);
System.out.println("队列中取得元素:"+obj);
putCondition.signal();
return obj;
} else {
takeCondition.await();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
return null;
}
}
}
ReentrantLock
什么是可重入
可重入是指同一个线程中可以多次去获取锁。
`
class LarZhuReentrantLock implements Lock{
//重入次数
AtomicInteger count =new AtomicInteger(0);
//锁拥有者
AtomicReference<Thread> owner =new AtomicReference();
//等待队列
private LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue();
@Override
public void lock() {
if(!tryLock()){
//将线程放入到waiting set
waiters.offer(Thread.currentThread());
while (true){
//若线程是队列头部,先判断一次,现在能不能去抢,然后再去加锁
Thread head = waiters.peek();
if(head==Thread.currentThread()){
if(!tryLock()){
// 没有抢到锁继续park
LockSupport.park();
}else{
//签到锁, 将线程出队列
waiters.poll();
return;
}
}else {
//伪唤醒后, 继续park。
LockSupport.park();
}
}
}else {
return;
}
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
//判断count时否为0 ,
if(count.intValue()!=0){
//锁被占用, 判断是否时当前线程
if (owner.get()== Thread.currentThread()){
count.set(count.intValue()+1);
return true;
}else {
return false;
}
}else{
if(count.compareAndSet(count.intValue(),count.intValue()+1)){
owner.set(Thread.currentThread());
return true;
}else{
return false;
}
}
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void unlock() {
if(tryUnlock()){
Thread head = waiters.peek();
if(head!=null){
LockSupport.unpark(head);
}
}
}
public boolean tryUnlock(){
if(owner.get()!=Thread.currentThread()) {
throw new IllegalMonitorStateException();
}else{
int ct = count.get();
int nextc = ct-1;
count.set(nextc);
if(nextc==0){ //可重入锁被加锁多次,一旦为0 就释放锁,如果不是0,还得继续释放
owner.compareAndSet(Thread.currentThread(),null);
return true;
}else{
return false;
}
}
}
@Override
public Condition newCondition() {
return null;
}
}