一些锁的概念

2020-04-28  本文已影响0人  superHang

悲观锁

悲观锁是指数据被外界修改保持保守状态,认为数据很容易会被其他线程修改,所以在数据的处理钱先对数据进行加锁处理,并在整个数据的处理过程中,使得数据处理锁定的状态

乐观锁

乐观锁是相对于悲观锁,他认为数据在一般的情况下不会造成冲突,所以在访问记录前不会加排他锁,而是在数据提交更新的时候才会正式对数据冲突与否进行检测。

公平锁

根据线程获取锁的抢占机制,区分公平锁和非公平锁,公平锁表示线程获取锁的顺序按照线程请求锁的时间早晚来决定,就是最早请求锁的线程将最早获取到锁

非公平锁

线程获取锁的顺序并不一定按照线程的先后顺序,比如A B C 3个线程,A获取锁了,那么B C 线程自然会被挂起,当A释放锁后,如果采取公平锁,那么C会被改期,B获取锁,而非公平锁的话,可能C先获取锁

独占锁 非独占锁

根据锁只能被单个线程持有还是多个线程持有分为独占锁和非独占锁
ReentrantLock就是以独占方式实现的。共享锁则可以同时由多个线程持有,例如ReadWriteLock读写锁,它允许一个资源可以被多线程同时进行读操作。
ReadWriteLock:
一次只有一个线程可以占有写模式的读写锁,但是多个线程可以同时占有读模式的读写锁。
只有一个线程可以占有写状态的锁,但可以有多个线程同时占有读状态锁,这也是它可以实现高并发的原因。当其处于写状态锁下,任何想要尝试获得锁的线程都会被阻塞,直到写状态锁被释放;如果是处于读状态锁下,允许其它线程获得它的读状态锁,但是不允许获得它的写状态锁,直到所有线程的读状态锁被释放;为了避免想要尝试写操作的线程一直得不到写状态锁,当读写锁感知到有线程想要获得写状态锁时,便会阻塞其后所有想要获得读状态锁的线程。所以读写锁非常适合资源的读操作远多于写操作的情况。

可重入锁

当一个线程要获取一个被其他线程持有的独占锁时,该线程会被阻塞,那么当一个线程再次获取它自己已经获锁,如果不被阻塞那么就说他是可重入锁
synchronized内部锁是可重入锁。可重入锁的原理是在锁内部维护一个线程标示,用来标示该锁目前被哪个线程占用,然后关联一个计数器。一开始
器值为0,说明该锁没有被任何线程占用。当一个线程获取了该锁时,计数器的值会变成1,这时其他线程再来获取该锁时会发现锁的所有者不是自己而被阻塞挂起。
但是当获取了该锁的线程再次获取锁时发现锁拥有者是自己,就会把计数器值加+1,当释放锁后计数器值-1。当计数器值为0时,锁里面的线程标示被重置为null,这时候被阻塞的线程会被唤醒来竞争获取该锁。

/**
     * 可重入锁,如果不是可重入锁的话,首先明确锁的是这个类,获取的是这个类的锁,
     * 然后 调用setA 的时候获取了这个类的锁了,如果不是可重入锁的话,那么SETB()
     * 就无法获取锁,导致这个setB 这个方法没法执行
     */
    public static  class TestLock{
        private int a;
        private int b;

        public static synchronized  void setA() {
            System.out.println("locak a");
            setB();
        }

        public  static  synchronized void setB() {
            System.out.println("lock b");
        }
    }

    public static void main (String[] args){
        TestLock.setA();
    }
image.png

自旋锁

Java中的线程是与操作系统中的线程一一对应的,所以当一个线程在获取锁(比如独占锁)失败后,会被切换到内核状态而被挂起。当该线程获取到锁时又需要将其切换到内核状态而唤醒该线程。而从用户状态切换到内核状态的开销是比较大的,在一定程度上会影响并发性能。自旋锁则是,当前线程在获取锁时,如果发现锁已经被其他线程占有,它不马上阻塞自己,在不放弃CPU使用权的情况下,多
次尝试获取(默认次数是10,可以使用-XX:PreBlockSpinsh参数设置该值),很有可能在后面几次尝试中其他线程已经释放了锁。如果尝试指定的次数后仍没有获取到锁则当前线程才会被阻塞挂起。由此看来自旋锁是使用CPU时间换取线程阻塞与调度的开销,但是很有可能这些CPU时间白白浪费了。

CAS算法

CAS是英文单词Compare and Swap(比较并交换),是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。CAS算法涉及到三个操作数

1.需要读写的内存值 V

2.进行比较的值 A

3.拟写入的新值 B

更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B,否则不会执行任何操作。一般情况下是一个自旋操作,即不断的重试。

上一篇下一篇

猜你喜欢

热点阅读