锁——数据同步离不开它

锁的种类:当我们刚接触到线程的时候,“锁”是一个不可避免的话题,按照锁的名称来说,可以有这些分类方式:
对象锁/类锁,公平锁/非公平锁,自旋锁,可重入锁,偏向锁/轻量级锁/重量级锁,悲观锁/乐观锁,共享锁/排它锁,读写锁,互斥锁,显式锁/隐式锁,内置锁等等。
对象锁:当synchronized修饰的是非静态方法或代码块时,代表锁住的是当前对象,使用格式有以下几种:
synchronized 方法名;
synchronized(this);
synchronized(任一对象);
前两者锁住当前对象,后者锁住任意一个对象
类锁:当synchronized修饰的是静态方法时或代码块,由于一个类中的静态方法和静态变量在内存中只有一份,所以,当将一个静态方法或代码块被关键字synchronized修饰时,此类的所有对象都将会共用同一把锁,将其称为类锁,使用格式有以下两种:
static synchronized 方法名;直接在静态方法中加入synchronized关键字进行修饰
synchronized(类的class对象);

公平锁:公平锁是严格按照线程启动的顺序进行执行,在线程请求时,如果资源正在被占用,线程将会放置到一个先进先出的队列中进行排队等候,然后按照先进先出的策略进行加锁
优点:所有线程都会得到资源
缺点:除了第一个线程,其他线程都会堵塞,CPU唤醒开销大
非公平锁:非公平锁允许插队,执行顺序抢占决定,在线程请求时,当新线程发现没有线程正在使用资源时,将会试图抢占资源,如果资源被占用,则同样加入队列
优点:CPU无需唤醒线程,减少开销
缺点:有些线程永远不能得到线程,导致饿死
实现:公平锁和非公平锁都可以使用ReentrantLock实现
默认非公平锁:ReentrantLock lock = new ReentrantLock();
构造器传入false仍是非公平锁:ReentrantLock lock = new ReentrantLock(false);
实现公平锁:传入true:ReentrantLock lock = new ReentrantLock(true);

/**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

FairSync()和NonFairSync()是ReentrantLock类的两个静态内部类,顾名思义,分别代表了公平锁和非公平锁
内部实现的主要区别在于:
非公平锁当线程进入时,直接判断锁状态值是否为0,为0代表锁没被占用,则可以直接使用,否则进入队列等待
公平锁当线程进入时,除了判断锁状态值,还需要判断有无正在等待线程,有则加入队列,否则获取锁

自旋锁:自旋锁的含义为:当一个线程尝试获取到锁未成功时,不会进入阻塞状态,而是不断地循环,试图获取锁,直至线程成功获取到锁
优点:不会进行线程间的切换,减少了不必要的操作,使程序执行速度加快
缺点:若当前线程执行时间过长,会导致其他线程一直自旋,极度消耗CPU
实现:利用CAS算法能够实现简单的自旋锁
互斥锁:当一个线程尝试获取锁失败时,进入阻塞状态

可重入锁:可重入锁可以理解为当同一线程获取了锁,并且进入了方法A中,该线程在A没有释放锁的时候,可以进入另一个方法B,例如在外层函数获得锁之后,并没有退出函数的情况下,内层函数仍然可以获取到该锁
常用的synchronized和ReentrantLock都是可重入锁
优点:可以在一定程度上避免死锁

偏向锁:在程序应用过程中往往会发现这样一件事:锁总是由同一个线程占用,而很少有竞争的发生,这种情况则可以使用偏向锁,,减少性能的消耗
轻量级锁:当偏向锁中出现线程竞争的情况时,获得偏向锁的线程会被挂起,偏向锁将会升级,成为轻量级锁,轻量级锁和偏向锁一样,同样是使用CAS来判断是否有线程在进行长期竞争,如果有竞争,将会膨胀为重量级锁
重量级锁:指的是当一个线程获取锁时,其他线程将会直接挂起,进入阻塞状态,与常用synchronized加锁类似

悲观锁:每次读取数据时都认为其他线程会对其进行更改,适用于多写的场景
乐观锁:每次读取数据时都认为其他线程不会对其进行更改,适用于多读的场景

共享锁:称为读锁,若线程对数据加上读锁,则所有线程都可以进行数据的读取,但无法进行数据的写入
排它锁:又称为写锁,若线程对数据加上写锁,则只有该线程能够对其读写操作,其他线程都无法
对数据做任何操作

显式锁:主要指lock
隐式锁:主要指synchronized
二者区别:

区别locksynchronized
层面接口关键字
分类显式锁隐式锁
释放需要手动释放锁不需要手动释放锁
使用指定起始结束位置加在方法或代码块上
大量线程时性能
异常没释放可能产生死锁自动释放,故不会产生死锁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值