《ReentrantLock与synchronized的区别》

目录

Synchronized同步锁

synchronized的用法:

ReentrantLock

ReentrantLock和Synchronized的区别


 

Synchronized同步锁

        使用Synchronized关键字将一段代码锁起来,同一时间只允许一个线程访问。只有获取了这把锁的线程才能访问这段代码,并且只有一个线程拥有这把锁。这样就保证了代码的安全性。

synchronized的用法:

        1.修饰实例方法:synchronized修饰实例方法,则用到的锁,默认为this当前方法调用对象。

        只有获取this锁的线程才能访问当前方法。同一时刻只有一个线程持有this锁。

	public synchronized void add() {
		
	}
	public void add1() {
	    synchronized(this) {
			
		}
	}
//使用synchronized关键字修饰方法时,两种写法作用与意义相同

        2.修饰静态方法 :修饰静态方法,用到的锁,默认为当前类的Class对象

	public synchronized static void add() {
		
	}

        3.修饰代码块:修饰代码块,用到的锁是可以指定的,为指定的某类对象。        

	Object obj = new Object();
	public void de() {
		synchronized(obj) {
			
		}
	}

         当一个线程访问对象的一个synchronized(this)同步代码块时,另一线程仍然可以访问该对象中的非synchronized(this)同步代码块。        

        父类中synchronized修饰的方法,如果子类没有重写,,则该方法仍然是线程安全的;如果子类重写,并没有使用synchronized修饰,则该方法是线程不安全的。

        定义接口方法时,不能使用synchronized关键字;

        构造方法不能使用synchronized关键字,但是可以使用synchronized代码块来进行同步。

        离开synchronized代码块后,该线程持有的锁,自动释放。

ReentrantLock

        ReentrantLock是Java中一种可重入锁。

        重入锁:一个线程,在获取锁后,可以继续获取同一个锁

                

public class Counter {
    private int count = 0;

    public synchronized void add(int n) {
        if (n < 0) {
            dec(-n);
        } else {
            count += n;
        }
    }

    public synchronized void dec(int n) {
        count += n;
    }
}
//当执行add()方法后,会继续调用dec()方法,dec方法也需要获取this锁。

         JVM允许同一个线程重复获取同一个锁,这种能被反复获取的锁,叫可重入锁。

        ReentrantLock是可重入锁,synchronized也是可重入锁。

        在获取可重入锁时,要记录这是第几次获取,没获取一次记录+1,每次退出可重入锁,记录-1,减到0时,才会真正释放锁。

public class Counter {
    private final Lock lock = new ReentrantLock();
    private int count;

    public void add(int n) {
        lock.lock();
        try {
            count += n;
        } finally {
            lock.unlock();
        }
    }
}

        ReentrantLock是JavaSE 核心类库的并发包(java.util.concurrent)提供的可重入锁,所以以防有异常发生,无法正常释放锁所以在创建锁后,在finally中释放锁。

        ReentrantLock还可以尝试获取锁:

                

if (lock.tryLock(1, TimeUnit.SECONDS)) {
    try {
        ...
    } finally {
        lock.unlock();
    }
}

尝试获取锁,最多等待一秒。一秒后,还未获取到锁,直接返回false,程序可以尝试做一些额外的处理,而不是无线等待。

        所以,ReentrantLock比synchronized更安全,在使用tryLock()失败后不会产生死锁。 

  ReentrantLock内部有三个类:Sync、NonfairSync、FairSync。

        NonfairSync类继承了Sync类,表示采用非公平策略获取锁:每一次都尝试获取锁,不会按照公平等待的原则进行等待,不会让等待最久的线程获得锁。

        FairSync类也继承了 Sync类,表示采用公平策略获取锁:当资源空闲时,它总是会先判断 sync队列是否有等待时间更长的线程,如果存在,则将当前线程加入到等待队列的尾部,实现了公平获取原则。

        ReentrantLock构造函数:默认是采用的非公平策略获取锁。

        ReentrantLock(boolean) 构造函数:可以传递参数确定采用公平策略或者是非公平策略,参数为 true表示公平策略,否则,采用非公平策略。

ReentrantLock和Synchronized的区别

        

ReentrantLock Synchronized
锁实现机制 AQS 监视器Monitor
获取锁 可以通过tryLock()尝试获取锁,更灵活 线程抢占模型
释放锁 必须显示通过unlock()释放锁 自动释放
锁类型 支持公平锁和非公平锁 非公平锁
可重入性 可重入 可重入

                

         

     

 

 

        

 

         

 

     

         

 

   

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