synchronized 关键字的用法
- 修饰实例方法:synchronized修饰实例方法, 则用到的锁,默认为this当前方法调用对象;
- 修饰静态方法:synchronized修饰静态方法, 则其所用的锁,默认为Class对象;
- 修饰代码块:synchronized修饰代码块, 则其所用的锁,是某个指定Java对象;
synchronized修饰实例方法
- 使用当前对象this充当锁,完成对当前方法的锁定,只有获取this锁的线程才能访问当前方法;
- 并发过程中,同一时刻,可以有N个线程请求执行方法,但只有一个线程可以持有this锁,才能执行;
- 不同线程,持有的对象,必须相同;
public class Foo{
//实例方法
public synchronized void dosth1(){
//获取this锁,才能执行该方法
}
//实例方法
public void dosth2(){
synchronized(this){
}
}
}
synchronized修饰静态方法
- 使用当前对象的Class对象充当锁,完成对当前方法的锁定,只有获取Class锁的线程才能访问当前方法;
- 不同线程,持有的对象,可以不同,但必须相同class类型
public class Foo{
//实例方法
public synchronized static void dosth1(){
//获取this锁,才能执行该方法
}
//实例方法
public static void dosth2(){
synchronized(this){
}
}
}
ReentrantLock
ReentrantLock实现了 Lock接口,Lock接口中定义了 lock()、 unlock()tryLock()等相关操作。
ReentrantLock总共有三个内部类:Sync、NonfairSync、FairSync。
NonfairSync 类继承了 Sync类,表示采用非公平策略获取锁:每一次都尝试获取锁,不会按照公平等待的原则进行等待,不会让等待时间最久的线程获得锁。
FairSync类也继承了 Sync类,表示采用公平策略获取锁:当资源空闲时,它总是会先判断 sync队列是否有等待时间更长的线程,如果存在,则将当前线程加入到等待队列的尾部,实现了公平获取原则。
ReentrantLock构造函数:默认是采用的非公平策略获取锁。
synchronized和reentrantlock都是Java中用于实现线程同步的机制,它们的主要区别如下:
锁的获取方式不同:synchronized是隐式锁,即在进入同步代码块或方法时自动获取锁,退出时自动释放锁;而reentrantlock是显式锁,需要手动获取和释放锁。
可重入性不同:synchronized是可重入锁,即同一个线程可以多次获取同一把锁,而reentrantlock也是可重入锁,但需要手动实现。
等待可中断性不同:synchronized不支持等待可中断,即线程无法响应中断请求,而reentrantlock支持等待可中断,可以响应中断请求。
公平性不同:synchronized是非公平锁,即无法保证等待时间最长的线程最先获取锁,而reentrantlock可以通过构造函数指定是否为公平锁。
性能不同:在低并发情况下,synchronized的性能优于reentrantlock,但在高并发情况下,reentrantlock的性能优于synchronized