你的位置:首页 > Java教程

[Java教程]java并发:Lock、ReentrantLock


Lock是一个接口,提供了无条件的、可轮询的、定时的、可中断的锁获取操作,所有加锁和解锁的方法都是显式的。

包路径是:java.util.concurrent.locks.Lock

核心方法是lock()、unlock()、tryLock()

实现类有ReentrantLock、ReentrantReadWriteLock.ReadLock、ReentrantReadWriteLock.WriteLock

下图展示了Lock接口中定义的方法:

 

 

 Java中synchronized 和 ReentrantLock 有什么不同?

Java在过去很长一段时间只能通过synchronized关键字来实现互斥,它有一些缺点。比如你不能扩展锁之外的方法或者块边界,尝试获取锁时不能中途取消等。Java 5 通过Lock接口提供了更复杂的控制来解决这些问题。ReentrantLock是Lock的实现类,它拥有与synchronized相同的并发性和内存语义且它还具有可扩展性。

 

 

此处我们看一下下面这两段代码,请注意这两种方式的区别:

(1)此处两个方法之间的锁是独立的

package com.test;import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockDemo {  public static void main(String[] args) {    final Countx ct = new Countx();    for (int i = 0; i < 2; i++) {      new Thread() {        @Override        public void run() {          ct.get();        }      }.start();    }    for (int i = 0; i < 2; i++) {      new Thread() {        @Override        public void run() {          ct.put();        }      }.start();    }  }}class Countx {  public void get() {    final ReentrantLock lock = new ReentrantLock();    try {      lock.lock();// 加锁      System.out.println(Thread.currentThread().getName() + "get begin");      Thread.sleep(1000L);// 模仿干活      System.out.println(Thread.currentThread().getName() + "get end");      lock.unlock(); // 解锁    } catch (InterruptedException e) {      e.printStackTrace();    }  }  public void put() {    final ReentrantLock lock = new ReentrantLock();    try {      lock.lock();// 加锁      System.out.println(Thread.currentThread().getName() + "put begin");      Thread.sleep(1000L);// 模仿干活      System.out.println(Thread.currentThread().getName() + "put end");      lock.unlock(); // 解锁    } catch (InterruptedException e) {      e.printStackTrace();    }  }}

运行结果如下(每次运行结果都是不一样的,仔细体会一下):

Thread-1get beginThread-0get beginThread-2put beginThread-3put beginThread-0get endThread-3put endThread-1get endThread-2put end

 

(2)此处两个方法之间使用相同的锁

package com.test;import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockDemo {  public static void main(String[] args) {    final Countx ct = new Countx();    for (int i = 0; i < 2; i++) {      new Thread() {        @Override        public void run() {          ct.get();        }      }.start();    }    for (int i = 0; i < 2; i++) {      new Thread() {        @Override        public void run() {          ct.put();        }      }.start();    }  }}class Countx {  final ReentrantLock lock = new ReentrantLock();  public void get() {    // final ReentrantLock lock = new ReentrantLock();    try {      lock.lock();// 加锁      System.out.println(Thread.currentThread().getName() + "get begin");      Thread.sleep(1000L);// 模仿干活      System.out.println(Thread.currentThread().getName() + "get end");      lock.unlock(); // 解锁    } catch (InterruptedException e) {      e.printStackTrace();    }  }  public void put() {    // final ReentrantLock lock = new ReentrantLock();    try {      lock.lock();// 加锁      System.out.println(Thread.currentThread().getName() + "put begin");      Thread.sleep(1000L);// 模仿干活      System.out.println(Thread.currentThread().getName() + "put end");      lock.unlock(); // 解锁    } catch (InterruptedException e) {      e.printStackTrace();    }  }}

运行结果如下(每次运行结果都是一样的):

Thread-0get beginThread-0get endThread-1get beginThread-1get endThread-2put beginThread-2put endThread-3put beginThread-3put end