面试相关 — Java【锁】


我们天天说锁,锁到底是什么?参考
涉及到知识点:

  1. volatile 可见性
  2. CAS 机制保证原子性操作
  3. 线程通信

锁保证竞争条件下,只能有一个线程去处理业务逻辑。
1、怎么表示锁被占用?被谁占用?
volatile修饰变量Thread owner,变量不为null,表示占用

2、如何保证锁的争夺是原子性的?
CAS机制 — 用一个预期的值和内存值进行比较,如果两个值相等,就用预期的值替换内存值,并返回 true。否则,返回 false。

private volatile AtomicReference<Thread> owner = new AtomicReference<Thread>();

// CAS机制拿当前线程跟主内存中的值对比,owner是否为null,如果是就将其值设置为当前线程
owner.compareAndSet(null, Thread.currentThread());

3、抢不到锁的线程如何阻塞?阻塞后改如何唤醒呢?
线程通信,park/unpark

4、抢不到锁的线程该怎么保存?
private volatile LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>();

释放锁:

public void unlock() {
    // CAS机制拿当前线程跟主内存中的值对比,是否是同一个线程,如果是就将其值设置为null
    if (owner.compareAndSet(Thread.currentThread(), null)) {
        // 将所有阻塞等待队列的线程都唤醒,让他们去抢锁。(非公平)
        if (CollectionUtils.isNotEmpty(waiters)) {
            waiters.stream().forEach(waiter -> {
                LockSupport.unpark(waiter);
            });
        }
    }
}

【线程AB交替打印AB】
参考

通过synchronized上锁,配合boolean变量完成交替打印

public class ThreadWhileDemo {

    private static boolean startA = true;
    private static boolean startB = false;

    public static void main(String[] args) {
        
        final Object singal = new Object();
        
        new Thread(() -> {
            // 上锁
            synchronized(singal){
                while (true) {
                    if (startA) {
                        System.out.print("A");
                        startA = false;
                        startB = true;
                        singal.notify();
                    }else{
                        try {
                            singal.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();

        new Thread(() -> {
            synchronized(singal){
                while (true) {
                    if (startB) {
                        System.out.print("B");
                        startA = true;
                        startB = false;
                        singal.notify();
                    }else{
                        try {
                            singal.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();

    }
}

ReentrantLock 可以实现手动加锁,同时配合Condition可以随心所欲地控制多个线程的执行顺序。

public class ReenterLockDemo {
    public static void main(String[] args) {

        ReentrantLock lock = new ReentrantLock();
        Condition conditionA = lock.newCondition();
        Condition conditionB = lock.newCondition();
        
        new Thread(() -> {
            
            lock.lock();
            
            for (int i = 0; i < 10; i++) {
                System.out.print("A");
                conditionB.signal();
                try {
                    conditionA.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 这里有个坑,要记得在循环之后调用signal(),否则线程可能会一直处于await状态
            conditionB.signal();

            lock.unlock();
        }).start();

        new Thread(() -> {
            
            lock.lock();

            for (int i = 0; i < 10; i++) {
                System.out.print("B");
                conditionA.signal();
                try {
                    conditionB.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            conditionA.signal();

            lock.unlock();
        }).start();

    }
}

【实现一个死锁】

主要思路:有两个锁,线程AB各把持一个

public class DeadLockDemo {

    public static void main(String[] args) {
        
        // 上两把锁
        final Object o1 = new Object();
        final Object o2 = new Object();

        // 通过lambda表达式,完成Runable implement
        new Thread(() -> {

            synchronized(o1){
                System.out.println("我上锁o1");

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized(o2){
                    System.out.println("我应该到不了这,谁知道呢");
                }
            }

        }).start();

        // 继承方式
        new Thread(){
            public void run() {
                synchronized(o2){
                    System.out.println("I lock o2");
                    synchronized(o1){
                        System.out.println("Unreachable site...");
                    }
                }
            };
        }.start();

    }

}

原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/274098.html

(0)
上一篇 2022年7月13日
下一篇 2022年7月13日

相关推荐

发表回复

登录后才能评论