显式锁与隐式锁的区别&同步代码块的理解
引言
在多线程的程序中,JAVA为了具体的控制每个线程的,所以有了锁机制,锁又被分为显式锁和隐式锁.
隐式锁(Synchronized)
隐式锁中又分为同步代码块和同步方法,但是都是基于Synchronized关键字来实现的,因为他只需要是使用管关键字就可以,不用显示加锁和解锁的过程,所以称之为隐式锁,具体的实现可以参考下面的代码:
同步代码块
public void method(){
synchronized(this){
//要锁住的代码
//一次只能有一个线程来指向这段代码
}
}
1.上面的代码是同步代码块,就是在代码块前面加上Synchroized关键字,并在后面的小括号内传入锁对象,这里的this是指定了当前的这个对象作为锁,注意任何对象都是可以作为锁来使用的.
2.这个是排队执行,一个线程进入代码块时,就会把这个锁对象的状态变成上锁状态,其他的线程发现是上锁状态时,就会在外面等待,直到这个线程将锁住的代码块执行完毕之后,将锁对象的状态变为解锁,其他的线程才会一起抢,谁抢到就重复上面的操作,知道满足某个条件,程序结束.
补充: 同步代码块理解
1、同步代码块的理解
public void test01(){
Synchronized(this){
//共享代码
}
}
上文中的this指代进入此代码块的线程对象,如果线程Thread1首先进到同步代码块后,会将同步代码块中的代码全部锁住,当线程Thread2也进到此处,线程Thread2只能处于等待状态,需要等到线程Thread1执行完同步代码后才能够进入。
这样的话,该方式比同步方法public synchronized void fun(){}更优越,因为,后者锁住了方法中所有的代码。
2、类同步的理解
public void test02(){
Synchronized(xx.class){
//共享代码
}
}
同步的是类对象,在不同线程中,只要是这个类的对象都会同步等待。
转载连接:https://blog.csdn.net/weixin_43334389/article/details/108790563
同步方法
public synchronized void method(){
//方法体
}
同步方法就是将Synchroized关键字方放在方法的返回值前面,这里的锁就是也就是this,谁调用它,谁就是他的锁.
原理跟同步代码块一样,但是这里的锁因为是this,如果在一个线程对象里有多个方法,那么第一个线程执行时给这个this上了锁,那么其他方法都是不能执行的.只有等一个方法执行完了之后,改变锁的状态,其他的才可以执行.
显式锁(Lock)
显式锁的概念是相对于隐式锁的,因为显式锁在使用的时候程序员可以控制上锁和解锁,所以称之为显式.显式锁是一个借口,不能直接使用,所以要使用它的实现类来进行操作,他一共有三个实现类,分别是ReentrantLock.ReentrantReadWriteLock.ReadLock和ReentrantReadWritLock.WritLock.因为现在只学了第一种,所以只来解释第一种.
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代码块里面.还要注意只有上了锁才能开锁,不上锁开锁系统会报异常.
两者的区别
Synchronized是内部实现的,不需要人为控制,jvm会在内部自动改变锁的状态,而Lock是需要上锁和解锁的.,而且只上锁不解锁或者只解锁不上锁都是不可以的
Synchronized是针对代码块来上锁的,就是如果代码运行到同步代码块或者同步方法外面,锁就会自动解开.
而Lock是针对于一个对象,不论你有多少的代码,只要上锁之后没有用unlock解锁,这个东西都是被锁住的,而且还会有异常,程序员还要对异常进行处理.这个虽然麻烦,但是他也提供了一个便利,就是开锁和解锁不必在同一个代码块里面,就增加了可操作性
因为隐式锁是jvm在检测和处理,所以在一般情况下,还是隐式锁比较好用.
原文链接:https://blog.csdn.net/weixin_45573037/article/details/106157406
显式锁与隐式锁的区别
转载:https://blog.csdn.net/weixin_48043585/article/details/109156214
解决的方法 格式 描述
同步代码块(关键字) synchronized(锁对象){} 隐式锁,多个线程的锁对象必须唯一
同步方法(修饰符) synchronized 返回类型 方法名(){} 隐式锁,谁调用该方法谁就是锁对象
显示锁 ReentrantLock类的lock()/unlock()方法 显式锁,有程序员决定在那开启/关闭锁
一、构成不同
Sync 和 Lock 的出身(原始的构成)不同:
Sync:Java中的关键字,是由JVM来维护的。是JVM层面的锁。
Lock:是JDK5以后才出现的具体的类。使用 Lock 是调用对应的API。是API层面的锁。
Sync 底层是通过 monitorenter 进行加锁(底层是通过 monitor 对象来完成的,其中的wait/notify等方法也是依赖于 monitor 对象的。只有在同步代码块或者同步方法中才可以调用wait/notify等方法。因为只有在同步代码块或者是同步方法中,JVM才会调用 monitory 对象);通过 monitorexit 来退出锁。
而 Lock 是通过调用对应的API方法来获取锁和释放锁。
二、使用方法不同
Sync是隐式锁;Lock是显示锁。
所谓的显示和隐式就是在使用的时候,使用者要不要手动写代码去获取锁和释放锁。
在使用sync关键字的时候,程序能够自动获取锁和释放锁。那是因为当sync代码块执行完成之后,系统会自动的让程序释放占用的锁。Sync是由系统维护的,如果非逻辑问题的话,是不会出现死锁的。
在使用lock的时候,我们使用者需要手动的获取和释放锁。如果没有释放锁,就有可能导致出现死锁的现象。手动获取锁方法:lock();释放锁:unlock()。
三、等待是否可中断
Sync是不可中断的。除非抛出异常或者正常运行完成。
Lock是可以中断的。中断方式:
调用设置超时方法tryLock(long timeout ,timeUnit unit)
调用lockInterruptibly()放到代码块中,然后调用interrupt()方法可以中断
四、加锁的时候是否公平
Sync:非公平锁。
Lock:两者都可以。默认是非公平锁,在其构造方法的时候可以传入Boolean值(true:公平锁;false:非公平锁)
五、锁绑定多个条件来condition
Sync:没有。要么随机唤醒一个线程;要么是唤醒所有等待的线程。
Lock:用来实现分组唤醒需要唤醒的线程,可以精确的唤醒,而不是像sync那样,不能精确唤醒线程。
本文详细比较了Java中的隐式锁(Synchronized)和显式锁(ReentrantLock),包括它们的构成、使用方法、中断能力、公平性以及如何控制多个条件。理解Synchronized的自动管理与Lock的灵活性,有助于提升多线程编程效率。

4648

被折叠的 条评论
为什么被折叠?



