一、什么是Synchronized同步锁
- synchronized是Java中用于实现线程安全的关键字,可以应用于方法或代码块上,用于实现线程安全的同步机制。
- synchronized控制多个线程对共享资源的访问,确保多个线程在同一时刻,只有一个线程可以执行某个方法或者代码块,保证了代码执行的一致性和原子性,防止出现数据不一致的情况。
- synchronized同步锁在加锁和解锁工程中,依赖于操作系统互斥锁(MutexLock)所实现的锁,小号资源,属于重量级锁。另外在获取锁时,必须一直等待,没有额外的尝试机制。
二、Synchronized关键字的用法
1. 修饰实例方法:synchronized修饰实例方法,则用到的锁,默认为 this 当前方法调用对象。
2. 修饰静态方法:synchronized修饰静态方法,则其所用的锁,默认为 Class 对象
3. 修饰代码块:synchronized修饰代码块,则其所用的锁,是某个指定的Java对象(自己指定锁对象)。
三、Synchronized的底层实现
synchronized代码块是由一对 monitorenter / monitorexit 指令实现,synchronized是通过对象的内部叫做监视器(monitor)来实现的,线程通过执行 monitorenter 指令尝试获取monitor的所有权,当monitor被占用时就会处于锁定状态。
四、锁升级(锁膨胀)
偏向锁:如果只有一个线程获得了锁,而且没有其他线程竞争,那么这个锁就会保持在偏向锁状态。如果发现有多于一个线程调用,再升级为轻量级锁。
轻量级锁:轻量级锁使用CAS(Compare and Swap)操作尝试获取锁,如果CAS成功,锁的持有者会变成当前线程;如果CAS失败(意味着其他线程正在尝试获取锁),当前线程将被挂起,并且锁会被升级为重量级锁。
重量级锁:需要在操作系统层面从用户态切换至内核态,实现操作系统级别的互斥锁,会带来额外性能的开销,降低效率。
五、Synchronized关键字的注意事项
1. 当一个线程访问对象的一个 synchronized(this) 同步代码块时,另一个线程仍然可以访问该对象中的非 synchronized (this) 同步代码块。
2.在没有加锁的情况下,所有的线程都可以自由地访问对象中的代码,而synchronized关键字只是限制了线程对于已经加锁的同步代码块的访问,并不会对其他代码做限制。所以,同步代码块应该越短小越好。
3. 父类中 synchronized 修饰的方法,如果子类没有重写,则该方法仍然是线程安全性;如果子类重写,并且没有使用 synchronized 修饰,则该方法不是线程安全的;
4. 在定义接口方法时,不能使用 synchronized 关键字;
5. 构造方法不能使用 synchronized 关键字,但可以使用 synchronized 代码块来进行同步;
6. 离开 synchronized 代码块后,该线程所持有的锁,会自动释放;
六、Synchronized和ReentrantLock的区别?
ReentrantLock | Synchronized | |
锁实现机制 | AQS | 监视器Monitor |
获取锁 | 可以通过tryLock() 尝试获取锁,更灵活 | 线程抢占模型 |
释放锁 | 必须显示通过unlock()释放锁 | 自动释放 |
锁类型 | 支持公平锁和非公平锁 | 非公平锁 |
可重入性 | 可重入 | 可重入 |
标签:释放,Synchronized,synchronized,代码,ReentrantLock,谈谈,理解,线程,修饰 From: https://blog.csdn.net/weixin_65978343/article/details/1423551671. 用法上的区别:
- synchronized 是一个关键字,可以用来修饰普通方法、静态方法以及代码块,语法简洁;
- ReentrantLock是一个类,需要实例化,然后调用lock()和 unlock()方法来获取和释放锁;
2.获取和释放锁的机制:
- synchronized 是自动加锁和释放锁的,当线程执行完 synchronized 代码块或者抛出异常时,锁会自动释放;
- ReentrantLock 需要手动加锁和释放锁,如果在执行过程中发生异常而没有显式调用 unlock()方法释放锁,可能会导致死锁;
3.锁类型:
- synchronized 默认是非公平锁,采用线程抢占模型:
- ReentrantLock默认也是非公平锁,但可以通过构造函数指定为公平锁,这样可以提高锁的公平性,但是会降低性能;
4.底层实现:
- synchronized是JVM级别的锁,通过监视器(Monitor)和JVM指令实现锁;
- ReentrantLock 是基于 Java 类库提供的锁,使用了 AbstractQueuedSynchronizer(AOS)框架来实现锁的逻辑;
5.异常处理:
- synchronized在发生异常时会自动释放锁,不会导致死锁;
- ReentrantLock需要在 finally 块中显式调用 unlock()方法来释放锁,否则可能会导致死锁;
6.性能差异:
- 早期版本的 Java中,ReentrantLock的性能优于synchronized
- 但随着 Java 6 和后续版本中 synchronized 的优化,两者在性能上的差异已经不大;
7.功能扩展:
- ReentrantLock 提供了更多功能:尝试获取锁(tryLock)、带超时的锁尝试、可中断的锁尝试,使用形式上更灵活: