在多线程环境下,一般咱们使用 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上查看个人视频。