JAVA中显式锁和隐式锁、公平锁和非公平锁

本文详细介绍了Java中多线程的锁机制,包括隐式锁(synchronized)和显式锁(Lock),以及公平锁与非公平锁的概念。隐式锁使用方便,由JVM自动管理锁的状态,而显式锁提供了更多的控制,如ReentrantLock支持公平竞争和读写分离。公平锁遵循先来先得原则,而非公平锁获取锁是随机的。ReentrantLock默认是非公平锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在多线程的程序中,JAVA为了具体的控制每个线程的,所以有了锁机制。所谓的显式锁和隐式锁,就是在使用的时候使用者是否需要手动写代码去获取锁和释放锁。显式锁使用Lock关键字,需要手动写代码去获取锁和释放锁。隐式锁使用synchronized修饰符,不需要手动写代码去获取锁和释放锁。

一、显式锁和隐式锁

1.隐式锁

隐式锁中又分为同步代码块和同步方法,但是都是基于Synchronized关键字来实现的,因为他只需要是使用管关键字就可以,不用显示加锁和解锁的过程,所以称之为隐式锁,具体的实现可以参考下面的代码:

同步代码块

public void method(){
    synchronized(this){
        //要锁住的代码,一次只能有一个线程来指向这段代码
    }
}

上面的代码是同步代码块,就是在代码块前面加上synchroized关键字,并在后面的小括号内传入锁对象,这里的this是指定了当前的这个对象作为锁,注意任何对象都是可以作为锁来使用的。这个是排队执行,一个线程进入代码块时,就会把这个锁对象的状态变成上锁状态,其他的线程发现是上锁状态时,就会在外面等待,直到这个线程将锁住的代码块执行完毕之后,将锁对象的状态变为解锁,其他的线程才会一起抢,谁抢到就重复上面的操作,知道满足某个条件,程序结束。

同步方法

public synchronized void method(){
        //方法体
}

同步方法就是将Synchroized关键字方放在方法的返回值前面,这里的锁就是也就是this,谁调用它,谁就是他的锁。原理跟同步代码块一样,但是这里的锁因为是this,如果在一个线程对象里有多个方法,那么第一个线程执行时给这个this上了锁,那么其他方法都是不能执行的。只有等一个方法执行完了之后,改变锁的状态,其他的才可以执行。

2.显式锁(Lock)

显式锁的概念是相对于隐式锁的,因为显式锁在使用的时候程序员可以控制上锁和解锁,所以称之为显式。显式锁是一个接口,它的实现类主要有三个,ReentrantLock 是其最主要的实现类,ReadLock 和 WriteLock 是 ReentrantReadWriteLock 内部定义的两个内部类,他们继承自 Lock 并实现了其定义的所有方法,精细化读写分离。而 ReentrantReadWriteLock 向外提供读锁、写锁。

public class Demo03 implements Runnable {
    Lock l = new ReentrantLock();
    @Override
    public void run() {
        l.lock();
        try{
            //要锁住的代码
        }catch(Exception e){
            //异常的处理逻辑
        }finally{
            l.unlock();
        }
    }
}

首先要在线程类里面定义一个锁对象,然后通过他的lock()方法来上锁,锁住的东西就是直到调用它unlock()方法开锁之前的所有代码,显式锁如果上锁,一定要记得在最后开锁,建议写在finally代码块里面。还要注意只有上了锁才能开锁,不上锁开锁系统会报异常。

3.两者的区别

(1)Synchronized是内部实现的,不需要人为控制,jvm会在内部自动改变锁的状态,而Lock是需要上锁和解锁的,而且只上锁不解锁或者只解锁不上锁都是不可以的。

(2)Synchronized是针对代码块来上锁的,就是如果代码运行到同步代码块或者同步方法外面,锁就会自动解开。而Lock是针对于一个对象,不论你有多少的代码,只要上锁之后没有用unlock解锁,这个东西都是被锁住的,而且还会有异常,程序员还要对异常进行处理。这个虽然麻烦,但是他也提供了一个便利,就是开锁和解锁不必在同一个代码块里面,就增加了可操作性。

(3)Synchronized 关键字结合对象的监视器,JVM 为我们提供了一种“内置锁”的语义,这种锁很简便,不需要我们关心加锁和释放锁的过程,我们只需要告诉虚拟机哪些代码块需要加锁即可,其他的细节会由编译器和虚拟机自己实现。可以将我们的“内置锁”理解为是 JVM 的一种内置特性, 所以一个很显著的问题就是,它不支持某些高级功能的定制,比如说,我想要这个锁支持公平竞争,我想要根据不同的条件将线程阻塞在不同的队列上,我想要支持定时竞争锁,超时返回,我还想让被阻塞的线程能够响应中断请求等等。这些特殊的需求是“内置锁”满足不了的,所以在 JDK 层面又引入了“显式锁”的概念,不再由 JVM 来负责加锁和释放锁,这两个动作释放给我们程序来做,程序层面难免复杂了些,但锁灵活性提高了,可以支持更多定制功能,但要求你对锁具有更深层次的理解。

二、公平锁与非公平锁

1.公平锁:表示线程获取锁的顺序是按照线程启动顺序来获取的,即先来先得、先进先出。

非公平锁:表示获取锁是随机获得的,先启动的也不能保证一定先获得锁。

2.公平锁与非公平锁的区别:

(1)公平锁的性能要比非公平锁的性能要低。

(2)ReentrantLock类默认的构造参数为false也就是默认是非公平锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值