在多線程環境下,一般咱們使用 synchronized 關鍵字來保證線程安全。java
大多數狀況下,用 synchronized 關鍵字就足夠了,但它也有一些缺點, 因此在 Java Concurrency 包中引入了 Lock API 。從Java 1.5版開始在 java.util.concurrent.locks 包中提供了處理併發的 Concurrency API 的 Lock 鎖接口和一些實現類來改進 Object 鎖定機制。安全
Java Lock API中的一些重要接口和類是:多線程
synchronized 塊本質上是可重入的,即若是一個線程鎖定了監視對象,而且另外一個同步塊須要鎖定在同一個監視對象上,則線程能夠進入該代碼塊。我認爲這就是類名是ReentrantLock的緣由。讓咱們經過一個簡單的例子來理解這個特性。併發
public class Test{ public synchronized foo(){ //do something bar(); } public synchronized bar(){ //do some more } }
若是一個線程進入 foo(),它就會鎖定Test對象,因此當它嘗試執行 bar() 方法時,容許該線程執行 bar() 方法,由於它已經在 Test 對象上持有鎖,即與 synchronized(this) 效果是同樣的。ide
如今讓咱們看一個簡單的例子,咱們將使用 Java Lock API 替換 synchronized 關鍵字。post
假設咱們有一個 Resource 類,其中包含一些操做,咱們但願它是線程安全的,以及一些不須要線程安全的方法。this
package com.journaldev.threads.lock; public class Resource { public void doSomething(){ //do some operation, DB read, write etc } public void doLogging(){ //logging, no need for thread safety } }
如今假設咱們有一個 Runnable 類,咱們將使用 Resource 方法。google
package com.journaldev.threads.lock; public class SynchronizedLockExample implements Runnable{ private Resource resource; public SynchronizedLockExample(Resource r){ this.resource = r; } @Override public void run() { synchronized (resource) { resource.doSomething(); } resource.doLogging(); } }
請注意,我使用 synchronized 塊來獲取 Resource 對象上的鎖。咱們能夠在類中建立一個虛擬對象,並將其用於鎖定的目的。spa
如今讓咱們看看咱們如何使用 Java Lock API 並重寫上面的程序而不使用 synchronized 關鍵字。咱們將在Java 中使用 ReentrantLock。線程
package com.journaldev.threads.lock; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ConcurrencyLockExample implements Runnable{ private Resource resource; private Lock lock; public ConcurrencyLockExample(Resource r){ this.resource = r; this.lock = new ReentrantLock(); } @Override public void run() { try { if(lock.tryLock(10, TimeUnit.SECONDS)){ resource.doSomething(); } } catch (InterruptedException e) { e.printStackTrace(); }finally{ //release lock lock.unlock(); } resource.doLogging(); } }
正如你所看到的,我正在使用 tryLock() 方法來確保個人線程只等待必定的時間,若是它沒有得到對象的鎖定,它只是記錄和退出。另外一個要注意的重點是使用 try-finally 塊來確保即便 doSomething() 方法調用拋出任何異常也會釋放鎖定。
基於以上細節和程序,咱們能夠很容易地得出 Java Lock 和同步之間的如下差別。
這就是 Java Lock 示例,Java 中的 ReentrantLock 以及使用 synchronized 關鍵字的比較分析。
做 者:
關於Pankaj
若是你走得這麼遠,那就意味着你喜歡你正在讀的東西。爲何不直接在Google Plus,Facebook或Twitter上與我聯繫。我很想直接聽到你對個人文章的想法和意見。
最近我開始建立視頻教程,因此請在Youtube上查看個人視頻。