synchronized和lock的使用分析(优缺点对比详解)

1.synchronizedjava

加同步格式:性能

synchronized(须要一个任意的对象(锁)){线程

     代码块中放操做共享数据的代码。对象

}
synchromized缺陷接口

synchronized是java中的一个关键字,也就是说是java语言的内置的特性。资源

若是一个代码块被synchronized修饰,当一个线程获取了对应的锁,并执行代码块时,其余线程只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种状况:同步

(1)获取锁的线程执行完了改代码块,而后线程释放对锁的占有源码

(2)线程执行发生异常,此时JVM会让线程自动释放锁。it

例子1:thread

若是这个获取锁的线程因为要等待IO或者其余缘由(好比调用sleep方法)被阻塞了,可是又没有释放锁,其余线程便只能干巴巴地等待,试想一下,这多么影响程序执行效率。

所以就须要有一种机制能够不让等待的线程一直无期限地等待下去(好比只等待必定的时间或者可以响应中断),经过Lock就能够办到。

例子2:

当有多个线程读写文件时,读操做和写操做会发生冲突现象,写操做和写操做会发生冲突现象,可是读操做和读操做不会发生冲突现象。

可是采用synchronized关键字来实现同步的话,就会致使一个问题:

若是多个线程都只是进行读操做,当一个线程在进行读操做时,其余线程只能等待没法进行读操做。

 

所以就须要一种机制来使得多个线程都只是进行读操做时,线程之间不会发生冲突,经过Lock就能够办到。

另外,经过Lock能够知道线程有没有成功获取到锁。这个是synchronized没法办到的。

总的来讲,也就是说Lock提供了比synchronized更多的功能。
 2.lock
lock和synchronized的区别

(1)lock不是java语言内置的,synchronized是java语言的关键字,所以是内置特性。lock是一个类,经过这个类能够实现同步访问;

(2)lock和synchronized有一点很是大的不一样,采用synchronized不须要用户手动的去释放锁,当synchronized方法或者代码块执行完毕以后,系统会自动的让线程释放对锁的占有,而lock则必需要用户去手动释放锁,若是没有主动的释放锁,就会可能致使出现死锁的现象

 
LOCK

首先要说明的就是,经过查看LOCK 的源码可知道,lock是一个接口

lock接口中每一个方法的使用:lock()、tryLock()、tryLock(long time, TimeUnit unit)、lockInterruptibly()是用来获取锁的。 unLock()方法是用来释放锁的。
四个获取锁方法的区别:

(1)lock()方法时日常使用的最多的一个方法,就是用来获取锁的,若是锁已经被其余线程获取,则进行等待。

          因为在前面讲到若是采用lock,必须主动去释放锁,而且在发生异常时,不会自动释放锁。所以通常来讲,使用lock必须在try{}catch{}块中进行,而且将释放锁的操做放在finally块中进行,以保证锁必定被释放掉,房主死锁的发生。

 (2)tryLock()方法是有返回值的,他表示用来尝试获取锁,若是获取成功,则返回true,若是获取失败(即锁已经被其余线程获取),则返回false,也就说这个方法不管如何都会当即返回。在拿不到锁时不会一直在哪里等待

(3)tryLock(long time, TimeUnit unit)方法和tryLock()方法时相似的,只不过区别在于这个方法在拿不到锁时会等待必定时间,在时间限制以内若是仍是拿不到锁,就返回false。若是一开始就拿到锁或者在等待期间内拿到了锁,则就返回true。

(4)lockinterruptibly()方法比较特殊,当经过这个方法区获取锁时,若是线程正在等待获取锁,则这个线程可以相应中断,即中断线程的等待状态。也就是说,当连个线程同时经过lock.lockinterruputibly()向获取某个锁时,假如此时线程A获取到了锁,而线程B只有等待,那么对线程调用threadB.interrupt()方法可以中断线程B的等待过程。

注意:当一个线程获取了锁以后,是不会被interrupt()方法中断的

所以当经过lockinterruptibly()方法获取某个锁时,若是不能获取到,只有进行等待的状况下,是能够相应中断的

而用synchronized修饰的话,当一个线程处于等待某个锁的状态,是没法被中断的,只有一直等待下去。

ReentrantLock

直接使用lock接口的话,咱们须要实现不少方法,不太方便,ReentrantLock是惟一实现了Lock接口的类,而且ReentrantLock提供了更多的方法,ReentrantLock,意思是“可重入锁”。

ReadWriteLock也是一个接口,在它里面只定义了两个方法:

一个用来获取读锁,一个用来获取写锁。也就是说将文件的读写操做分开,分红2个锁来分配给线程,从而使得多个线程能够同时进行读操做。ReentrantReadWriteLock实现了ReadWriteLock接口。

ReentrantReadWriteLock

ReentrantReadWriteLock里面提供了不少丰富的方法,不过最主要的两个方法:readlock()和writelock用来获取读锁和写锁

注意:

不过要注意的是,若是有一个线程已经占用了读锁,则此时其余线程若是要申请写锁,则申请写锁的线程会一直等待释放读锁。

若是有一个线程已经占用了写锁,则此时其余线程若是申请写锁或者读锁,则申请的线程会一直等待释放写锁。

 
3.LOCK和SYNCHRONIZED的选择

(1)lock是一个接口,而synchronized是java的关键字,synchronized是内置的语言实现;

(2)synchronized在发生异常时,会自动释放线程占有的锁,所以不会致使死锁现象发生;而lock在发生异常时,若是没有主动经过unlock()去释放锁,则极可能形成死锁现象,所以使用lock()时须要在finally块中释放锁;

(3)lock可让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不讷讷狗狗响应中断

(4)经过lock能够知道有没有成功获取锁,而synchronized却没法办到

(5)lock能够提升多个线程进行读操做的效率

在性能上来讲,若是竞争资源不激烈,二者的性能是差很少的,而竞争资源很是激烈是(既有大量线程同时竞争),此时lock的性能要远远优于synchronized。因此说,在具体使用时适当状况选择。  

相关文章
相关标签/搜索