ReentrantLock与synchronized的区别

Synchronized同步锁

Synchronized同步锁,简单来说,使用Synchronized关键字将一段代码逻辑,用一把锁给锁起来,只有获得了这把锁的线程才访问。并且同一时刻, 只有一个线程能持有这把锁, 这样就保证了同一时刻只有一个线程能执行被锁住的代码,从而确保代码的线程安全。

public static void main(String[] args) {
    // 实例化一个对象
    Foo fa = new Foo();
	
    // 创建不同的线程1
    Thread thread01 = new Thread() {
        public void run() {
            // 使用相同的对象访问synchronized方法
            fa.doSth1();
        }
    };
	
    // 创建不同的线程2
    Thread thread02 = new Thread() {
        public void run() {
            // 使用相同的对象访问synchronized方法
            fa.doSth1();
        }
    };
    
    // 启动线程
    thread01.start();
    thread02.start();
}



public class Foo {
    // 实例方法
    public synchronized void doSth1() {
        // 获取this锁,才能执行该方法
    }
    
    // 实例方法
    public void doSth2() {
        synchronized(this) {
           // 获取this锁,才能执行该代码块
        }
    }
}

synchronized 是 Java 内建的同步机制,它提供了互斥的语义和可见性,当一个线程已经获取当前锁时,其他试图获取的线程只能阻塞在那里。
在 Java 5 以前,synchronized是仅有的线程同步手段。在代码中, synchronized 可以用来修饰方法,也可以使用在特定的代码块上,本质上 synchronized 方法等同于把方法全部语句用 synchronized 块包起来。
synchronized同步锁在加锁和解锁的过程中,依赖于操作系统互斥锁(Mutex Lock)所实现的锁,消耗资源,属于重量级锁(在Java1.6以后进行了优化)。另外在获取锁时,必须一直等待,没有额外的尝试机制。

使用synchronized保证线程安全,就是保证原子性,简单说就是执行过程中不会被其他线程干扰。

public class ThreadSafeSample {
	public int sharedState;
    
	public void nonSafeAction() {
    	while (sharedState < 100000) {
            
        	int former = sharedState++;
        	int latter = sharedState;
            
        	if (former != latter - 1) {
            	System.out.printf("数据观察结果: former is %d,latter is %d",					former,latter);
        	}
    	}
	}

	public static void main(String[] args) throws InterruptedException {
    	ThreadSafeSample sample = new ThreadSafeSample();
    	Thread threadA = new Thread(){
        	public void run(){
            	sample.nonSafeAction();
        	}
    	};
    	Thread threadB = new Thread(){
        	public void run(){
            	sample.nonSafeAction();
        	}
 	   };
        
    	threadA.start();
    	threadB.start();
        
    	threadA.join();
    	threadB.join();

        System.out.println(sample.sharedState);
	}
}

ReentrantLock

ReentrantLock实现了 Lock接口,Lock接口中定义了 lock()、 unlock()tryLock()等相关操作。

ReentrantLock总共有三个内部类:Sync、NonfairSync、FairSync。
NonfairSync 类继承了 Sync类,表示采用非公平策略获取锁:每一次都尝试获取锁,不会按照公平等待的原则进行等待,不会让等待时间最久的线程获得锁。
FairSync类也继承了 Sync类,表示采用公平策略获取锁:当资源空闲时,它总是会先判断 sync队列是否有等待时间更长的线程,如果存在,则将当前线程加入到等待队列的尾部,实现了公平获取原则。
ReentrantLock构造函数:默认是采用的非公平策略获取锁。

ReentrantLock

Synchronized

锁实现机制

AQS

监视器Monitor

获取锁

可以通过tryLock()尝试获取锁,更灵活

线程抢占模型

释放锁

必须显示通过unlock()释放锁

自动释放

锁类型

支持公平锁和非公平锁

非公平锁

可重入性

可重入

可重入

synchronized和reentrantlock都是Java中用于实现线程同步的机制,它们的主要区别如下:

  1. 锁的获取方式不同:synchronized是隐式锁,即在进入同步代码块或方法时自动获取锁,退出时自动释放锁;而reentrantlock是显式锁,需要手动获取和释放锁。

  2. 可重入性不同:synchronized是可重入锁,即同一个线程可以多次获取同一把锁,而reentrantlock也是可重入锁,但需要手动实现。

  3. 等待可中断性不同:synchronized不支持等待可中断,即线程无法响应中断请求,而reentrantlock支持等待可中断,可以响应中断请求。

  4. 公平性不同:synchronized是非公平锁,即无法保证等待时间最长的线程最先获取锁,而reentrantlock可以通过构造函数指定是否为公平锁。

  5. 性能不同:在低并发情况下,synchronized的性能优于reentrantlock,但在高并发情况下,reentrantlock的性能优于synchronized。

你可能感兴趣的:(java,jvm,开发语言)