什么是锁?

简介: 什么是锁?

什么是锁?


说到锁,门闩,密码锁,指纹锁,虹膜识别锁等,在计算机世界中,单机线程没有锁的概念,当有了资源竞争,才有锁的贵爱安出现。表示自己短暂的持有。

计算机锁从最开始的悲观锁,然后发展到后来的乐观锁,偏向锁,分段锁等。

锁有两种特性:互斥性和不可见性。


JUC 中的锁


并发包的类族,Lock 是 JUC 包的顶层接口。实现逻辑并未用到 synchronized ,而是利用 volatile 的可见性。


640.png



Lock 的继承类图,ReentrantLock 对于 Lock 接口的实现主要依赖了 Sync, 而 Sync 继承了 AbstractQueuedSynchronizer(AQS), AQS 是实现同步的基础工具。


在 AQS 中定义了,定义了一个 volatile int state 变量作为共享资源,如果线程获取资源失败,则进入 同步的 FIFO  队列;如果成功获取资源就执行临界区代码。


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

AQS 的子类可以定义不同性质的方法。


  • 比如可重入锁 ReentrantLock ,定义 State 为0 时,可以获取资源并设置1,如果已经获得资源,state 不断+1 ,释放资源 state-1 直到为0;
  • CountDown 初始化定义资源总量 state=count ,CountDown() 不断将 state-1 ,所以 CountDownLatch 是一次性的,用完之后只能重建一个,如果要循环使用,推进使用 CyclicBarrier 。
  • Semaphore 与 CountDownLatch 不同,定义了资源总量 state=permits. 当state >0 就可以获得锁,并将 state-1.当 state=0时只能等待其他线程释放锁。当释放锁时  state+1。当 Semaphore 的permits定义为1时,为互斥锁。permits>1 为共享锁。


CyclicBarrier 例子


每次 await 都会  count-1


int index = --count;

测试代码:


public class CyclicBarrierSample {
    /**
     * @param args
     */
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(5, new Runnable() {
            @Override
            public void run() {
                System.out.println("Action.... go again!");
            }
        });
        for (int i = 0; i < 5; i++) {
            Thread t = new Thread(new CyclicWorker(barrier));
            t.start();
        }
    }
}
class CyclicWorker implements Runnable {
    private CyclicBarrier barrier;
    public CyclicWorker(CyclicBarrier barrier) {
        this.barrier = barrier;
    }
    /**
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run() {
        try {
            for (int i = 0; i < 3; i++) {
                System.out.println("Executed!");
                barrier.await();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}

CountDownLatch 代码


public class LatchSample {
    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(6);
        for(int i = 0; i < 5 ; i++){
            Thread t = new Thread(new FirstBatchWorker(latch));
            t.start();
        }
        for(int i = 0 ; i < 5;i++){
            Thread t = new Thread(new SecondBatchWorker(latch));
            t.start();
        }
        while(latch.getCount() != 1){
            Thread.sleep(100L);
        }
        System.out.println(" wait gor first batch finish");
        latch.countDown();
    }
}
class FirstBatchWorker implements Runnable {
    private CountDownLatch latch;
    public FirstBatchWorker(CountDownLatch latch) {
        this.latch = latch;
    }
    /**
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run() {
        System.out.println("First batch executed!");
        latch.countDown();
    }
}
class SecondBatchWorker implements Runnable {
    private CountDownLatch latch;
    public SecondBatchWorker(CountDownLatch latch) {
            this.latch = latch;
    }
    @Override
    public void run() {
        try {
            latch.await();
            System.out.println("Second batch Executed!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


相关文章
|
4月前
|
SQL 关系型数据库 MySQL
MySQL使用行级锁时,并非直接锁定记录,而是锁定涉及的索引。对于表`user_item`,更新语句先锁定非主键索引`idx_1`,再锁定主键索引。若两条更新语句分别按不同顺序锁定这两个索引,可能导致互相等待对方释放锁,引发死锁。解决方案包括先查询待更新记录的主键,再按主键更新,确保一致的锁定顺序。
43 2
|
4月前
|
SQL 关系型数据库 MySQL
临键锁引发的死锁
【8月更文挑战第4天】
44 0
临键锁引发的死锁
|
7月前
|
存储 安全 Java
12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
82 1
12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
|
Linux API C++
锁、避免死锁等相关
锁、避免死锁等相关
69 0
《锁》有那些?
锁是计算机科学中用于控制对共享资源的访问的一种同步机制。不同种类的锁适用于不同的场景和需求。下面是一些常见的锁的种类及其详细介绍:
78 1
|
存储 算法 安全
辛辛苦苦的劳动成果,如何上把锁?
辛辛苦苦的劳动成果,如何上把锁?
|
数据可视化 Java
lock锁和死锁
lock锁和死锁
共享锁(读锁)和排他锁(写锁)
共享锁(读锁)和排他锁(写锁)
161 0
|
存储 对象存储
|
PHP
并发锁(二):共享锁和独占锁
并发锁(二):共享锁和独占锁
216 0
并发锁(二):共享锁和独占锁