AQS对基本概念的实现

非公平锁

公平锁如何实现的呢?我们来看看 ReentranLock 中的 NonfairSync 类,这个类中就实现了对非公平锁的实现。

final void lock() {
    if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

这段逻辑中,我们可以发现,线程是直接取修改 state 的状态,这代表竞争锁,如果竞争到锁,就执行业务逻辑,如果竞争不到锁再执行 acquire 方法。不排队就是非公平锁。

公平锁

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;
}

公平锁呢,就需要先看看队列中是否有等待的线程,如果没有才取竞争锁,如果等待的队列中有线程,则返回 false , 线程进入排队的逻辑。

可重入

先来探讨一下,在什么情况下需要锁的可重入性。我们现在知道了 sychronized 这个关键字修饰方法的方法,其实是在对象头上上的锁。所以下面代码中,

public class ReentranTest {
    public static synchronized void add(){
        System.out.println("add in");
        update();
        System.out.println("add out");

    }

    private static synchronized void update() {
        System.out.println("update in ");
        System.out.println("do something");
        System.out.println("update out ");
    }

    public static void main(String[] args) {
        add();
    }

执行的结果如下所示:

add in
update in 
do something
update out 
add out

在执行某个操作的时候,需要先调用 add ,然后在 add 中,调用 update() 此时,同一个线程是可以进入的。如果 sychronized 底层代码没有考虑可重入性,那么当执行到 update() 的时候,状态(这里比较复杂,sychronized 涉及到了锁的升级,这个升级已经考虑了可重入性)已经被改变了,update 方法是不能进入的。我们拿 ReetrantLock 来说明吧,请看下面的例子,如下面的例子:

package interview;

import java.util.concurrent.locks.ReentrantLock;

public class ReentranTestV2 {
    public static ReentrantLock lock = new ReentrantLock();
    public static void add(){
        lock.lock();
        try {
            System.out.println("add in");
            update();
            System.out.println("add out");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }

    private static void update() {
        lock.lock();
        try {
            System.out.println("update in ");
            System.out.println("do something");
            System.out.println("update out ");
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        add();
    }
}

当执行当 update() 的时候,同一个线程会再次申请同一把锁,如果锁不能重入 ,则线程会死锁在 update() 代码里面。从 ReetrantLock 的 tryAquire() 代码中可以看到,如果不进行可重入处理,那么会返回 false,则进行入等待队列的环节,这样的话就自己被自己锁住了。

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;
}

条件队列

条件队列是一个进程间通信的问题。它是协调多个线程间行为的。例如,1A2B3C的问题。下面是代码,其中,前面两个都是解决 A B C 交题打印的问题,第三个是交替打印 100 次的逻辑。其实解题的思路都是以 flag 这个变量为核心,flag 好比指示灯,不同的指示灯亮起对应着响应线程的动作。具体到每个线程的逻辑就是,当竞争到锁的线程进入到逻辑代码中,先判断 flag 的值,符合条件则执行打印代码,否则执行等待。

import java.util.concurrent.CountDownLatch;
/**
 * 使用的 sychronized 关键字的方式。
 * 这个解题的思路的关键是什么时候该掉 wati 方法和 notify 方法。
 * 当条件不满足的时候,则调用 wait 方法
 * 当满足条件的时候,则执行逻辑代码,最后执行 notify 方法,唤醒其他等待着的线程
 * */
public class A1B2C3 {
    private static int flag = 0 ;
    public static void main(String[] args) {
        Object lock = new Object();
        CountDownLatch cdl = new CountDownLatch(3);
        Thread thread = new Thread(()->{
            synchronized (lock){
                while(flag != 0){
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("A");
                flag = 1 ;
                lock.notifyAll();
                cdl.countDown();
            }
        });

        Thread thread1 = new Thread(()->{
            synchronized (lock){
                while(flag != 1){
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("B");
                flag = 2 ;
                lock.notifyAll();
                cdl.countDown();
            }
        });
        Thread thread2 = new Thread(()->{
            synchronized (lock){
                while(flag != 2){
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("C");
                lock.notifyAll();
                cdl.countDown();
            }
        });
        thread.start();
        thread1.start();
        thread2.start();
        try {
            cdl.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 和  A1B2C3 的解题思路是一样的
 * */
public class A1B2C3Version2 {
    private static int flag = 0 ;
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        CountDownLatch cdl = new CountDownLatch(3);
        Thread thread = new Thread(()->{
            lock.lock();
            try{
                while(flag != 0){
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("A");
                flag = 1 ;
                condition.signalAll();
                cdl.countDown();
            }finally {
                lock.unlock();
            }
        });

        Thread thread1 = new Thread(()->{
            lock.lock();
            try{
                while(flag != 1){
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("B");
                flag = 2 ;
                condition.signalAll();
                cdl.countDown();
            }finally {
              lock.unlock();
            }
        });
        Thread thread2 = new Thread(()->{
            lock.lock();
            try {
                while (flag != 2) {
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("C");
                condition.signalAll();
                cdl.countDown();
            }finally {
                lock.unlock();
            }
        });
        thread.start();
        thread1.start();
        thread2.start();
        try {
            cdl.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 这个题目是,使用三个线程接替打印 0 , 1, 2 三个数字,最后的结果是:
 * 0
 * 1
 * 2
 * 0
 * 1
 * 2
 * ...
 * 0
 * 1
 * 2
 * 这个思路其实和 A1B2C3 的思路差不多,在不符合条件的时候,执行 await 方法
 * 然后等待其他线程执行完毕 sigianl 线程,唤醒当前线程。
 * */
public class A1B2C3for {
    private static int flag = 0 ;
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        List<Integer> list = new ArrayList<Integer>();
        Thread thread = new Thread(()->{
            for(int i = 0 ; i < 100 ; i++){
                lock.lock();
                try{
                    while (flag != 0 ){
                        try {
                            condition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    list.add(flag);
                    flag = 1 ;
                    condition.signalAll();
                }finally {
                    lock.unlock();
                }
            }
        });
        Thread thread2 = new Thread(()->{
            for(int i = 0 ; i < 100 ; i++){
                lock.lock();
                try{
                    while (flag != 1 ){
                        try {
                            condition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    list.add(flag);
                    flag = 2;
                    condition.signalAll();
                }finally {
                    lock.unlock();
                }
            }
        });
        Thread thread3 = new Thread(()->{
            for(int i = 0 ; i < 100 ; i++){
                lock.lock();
                try{
                    while (flag != 2 ){
                        try {
                            condition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    list.add(flag);
                    flag = 0;
                    condition.signalAll();
                }finally {
                    lock.unlock();
                }
            }
        });
        thread.start();
        thread2.start();
        thread3.start();
        try {
            thread.join();
            thread.join();
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i = 0 ; i < 300 ; i++){
            if(i%3 != list.get(i) ){
                System.out.println("false , index:" + i);
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值