ReentrantLock 可重入锁指的是 同一个线程可多次获取同一把锁
package test.BingFa;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
final static ExecutorService exec = Executors.newFixedThreadPool(4);
final static ReentrantLock lock = new ReentrantLock();
final Condition con = lock.newCondition();
final int time = 3;
static Runnable add = new Runnable() {
public void run() {
System.out.println("Pre " + lock);
lock.lock();
try {
System.out.println("试图获取锁 ");
// con.await(time, TimeUnit.SECONDS);
}
// catch (InterruptedException e) {
//
// e.printStackTrace();
//
// }
finally {
// con.signal();
System.out.println("Post " + lock.toString());
lock.unlock();
}
}
};
static Runnable addTryLock = new Runnable() {
public void run() {
System.out.println("Pre " + lock);
while (true) {
if (lock.tryLock()) {
try {
System.out.println("试图获取锁 ");
// con.await(time, TimeUnit.SECONDS);
}
// catch (InterruptedException e) {
//
// e.printStackTrace();
//
// }
finally {
// con.signal();
System.out.println("Post " + lock.toString());
lock.unlock();
}
break; //不然 无限制执行
}
}
}
};
public static void main(String[] args) throws InterruptedException {
for (int index = 0; index < 4; index++)
exec.submit(add);
//exec.submit(addTryLock);
exec.shutdown();
}
}
//exec.submit(addTryLock);
打开可以测试 try lock
以下转载
Lock和Condition
1、jdk1.5之前用synchornized和voatile来控制共享对象的并发访问,jdk5.0提供了ReentrantLock。
2、Lock和ReentrantLock:
Lock接口里定义了一些抽象的锁操作,有无条件、可轮询、定时、可中断的锁获取操作,ReentrantLock实现了Lock接口,获得ReetrantLock的锁与进入synchronized代码块有相同的内存语义,释放ReentrantLock锁和退出sychronized代码块有相同的内存语义。
从上面可以看出,Lock提供了不同形式获取锁方式,而之前通过synchronied修饰代码块的时候,如果有一个线程已经获取对象锁,其他线程访问共享对象的时候就必须无限等待,等待当前线程释放对象锁后再去进行竞争,不能中断那些等待获取锁的线程,而Lock提供了一些其他方法,比如tryLock():如果当前锁可用则获取并返回true,如果不可用则返回false。在方法前加上while(true)就可以实现轮询获取锁。
Java代码
- package com.sxit.test;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- /**
- * @功能:tryLock使用
- * @作者: smile
- * @时间:2013-4-18 下午4:03:18
- * @版本:1.0
- */
- public class TryLockDemo {
- // 锁
- private final Lock lock = new ReentrantLock();
- public void take() {
- if (lock.tryLock()) {
- try {
- System.out.println("take获取到锁...");
- } catch (Exception e) {
- e.printStackTrace();
- } finally{
- lock.unlock();
- }
- }else{
- System.out.println("take没有获取到锁...");
- }
- }
- public void put() {
- if (lock.tryLock()) {
- try {
- System.out.println("put获取到锁...");
- } catch (Exception e) {
- e.printStackTrace();
- } finally{
- lock.unlock();
- }
- }else{
- System.out.println("put没有获取到锁...");
- }
- }
- public static void main(String[] args) {
- TryLockDemo t = new TryLockDemo();
- Take take = new Take(t);
- Put put = new Put(t);
- Thread t1 = new Thread(take);
- Thread t2 = new Thread(put);
- t1.start();
- t2.start();
- }
- }
- class Take implements Runnable {
- private TryLockDemo t;
- public Take(TryLockDemo t) {
- this.t = t;
- }
- @Override
- public void run() {
- while (true) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- t.take();
- }
- }
- }
- class Put implements Runnable {
- private TryLockDemo t;
- public Put(TryLockDemo t) {
- this.t = t;
- }
- @Override
- public void run() {
- while (true) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- t.put();
- }
- }
- }
通过使用tryLock方法就可以让那些等待线程可以不用再无限期等待,可以继续轮询获取锁或者做其他操作。
tryLock还有一个指定时间获取锁的方法,在指定时间内如果锁可用则返回,不可用则线程处于休眠状态。
Java代码
- package com.sxit.test;
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- /**
- * @功能:tryLock使用
- * @作者: smile
- * @时间:2013-4-18 下午4:03:18
- * @版本:1.0
- */
- public class TryLockDemo {
- // 锁
- private final Lock lock = new ReentrantLock();
- public void take() throws Exception {
- if (lock.tryLock(100,TimeUnit.NANOSECONDS)) {
- try {
- System.out.println("take获取到锁...");
- } catch (Exception e) {
- e.printStackTrace();
- } finally{
- lock.unlock();
- }
- }else{
- System.out.println("take 100纳秒内没有获取到锁...");
- }
- }
- public void put() throws Exception {
- if (lock.tryLock(100,TimeUnit.NANOSECONDS)) {
- try {
- System.out.println("put获取到锁...");
- } catch (Exception e) {
- e.printStackTrace();
- } finally{
- lock.unlock();
- }
- }else{
- System.out.println("put 100纳秒内没有获取到锁...");
- }
- }
- public static void main(String[] args) {
- TryLockDemo t = new TryLockDemo();
- Take take = new Take(t);
- Put put = new Put(t);
- Thread t1 = new Thread(take);
- Thread t2 = new Thread(put);
- t1.start();
- t2.start();
- }
- }
- class Take implements Runnable {
- private TryLockDemo t;
- public Take(TryLockDemo t) {
- this.t = t;
- }
- @Override
- public void run() {
- while (true) {
- try {
- t.take();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
- class Put implements Runnable {
- private TryLockDemo t;
- public Put(TryLockDemo t) {
- this.t = t;
- }
- @Override
- public void run() {
- while (true) {
- try {
- t.put();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
还有一种是lockInterruptibly():可中断的锁获取,当线程在获取锁的时候,如果有其他线程调用该线程的interrupt方法中断线程,这时不会再去尝试获取锁,而会抛出一个InterruptedException异常。而正常的lock()方法不允许中断线程,即使调用了interrupt()方法还是会继续尝试获取锁,最后获取到锁后再把线程设置为interrupt状态,然后再中断。 而且使用lockInterruptibly获取锁的时候,如果线程被中断了,会抛出异常,并且会把线程的中断状态移除。
Java代码
- package com.sxit.test;
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- /**
- * @功能:lockInterruptibly使用
- * @作者: smile
- * @时间:2013-4-18 下午4:03:18
- * @版本:1.0
- */
- public class TryLockDemo {
- // 锁
- private final Lock lock = new ReentrantLock();
- public void interrupt() {
- try {
- lock.lockInterruptibly();
- System.out.println("打印一下");
- //中断前状态
- System.out.println("中断前状态:"+Thread.currentThread().isInterrupted());
- //中断当前线程
- Thread.currentThread().interrupt();
- //中断后状态
- System.out.println("中断后状态:"+Thread.currentThread().isInterrupted());
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- //中断最后状态
- System.out.println("中断最后状态:"+Thread.currentThread().isInterrupted());
- lock.unlock();
- }
- }
- public static void main(String[] args) {
- TryLockDemo t = new TryLockDemo();
- Iterrupt i = new Iterrupt(t);
- Thread t1 = new Thread(i);
- t1.start();
- }
- }
- class Iterrupt implements Runnable {
- private TryLockDemo t;
- public Iterrupt(TryLockDemo t) {
- this.t = t;
- }
- @Override
- public void run() {
- while (true) {
- try {
- t.interrupt();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
还有一个方法是newCondition(),返回一个Condition实例。这个方法时返回一个绑定这个Lock实例的条件对象实例。
之前使用synchronized的时候,比如生产者和消费者模型中有take和put两个操作,当队列为空时会调用list.wait(),当队列满的时候也会调用list.wait(),就是把当前线程加入到list对象的锁等待池中,而当队列不为空或者队列不是满的时候我们会调用notifyAll或者notify,比如take中调用notify时,它会从锁等待池中随机选一个线程让它进入可运行状态,等待锁释放后去竞争锁,但是这里就有一个问题,其实我们这里需要唤醒的是take线程,但是使用notify的时候随机性很强,很有可能他唤醒的是一个put线程或者别的线程,当然可以使用notifyAll,他会唤醒对象锁池中的所有线程,但是等锁释放后,还是只有一个锁能够竞争到资源进入运行状态,所以这样不能明确快速的指定具体要唤醒的线程。
现在jdk5.0提供了Condition,通过lock.newCondition()可以获得绑定当前锁的条件对象,每个条件对象都维护相对于自己这个条件的线程等待池,比如队列非空,可以创建一个Condition not_empty = lock.newCondition(); 当take的时候如果队列为空,则not_empty.await(),这样当前线程由这个条件对象来维护,当队列非空的时候就可以通过调用not_empty.sigal()来唤醒那些需要取元素的线程。这样就能把各种线程在不同条件下进行细致分类,灵活操作。不用像之前那样直接用个notifyAll,使用notifyAll把不同条件需求的线程全绑定在一个队列中,一个条件满足就需要唤醒全部线程,然后相互竞争锁,既不精确性能也差。
一个简单的生产者和消费者模型实例:
Java代码
- package com.sxit.test;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- /**
- * @功能:使用Lock Conditon
- * @作者: smile
- * @时间:2013-4-18 下午5:18:07
- * @版本:1.0
- */
- public class Test05 {
- public static Lock lock = new ReentrantLock();;
- // 容器已满 綁定product線程
- public static Condition full = lock.newCondition();
- // 容器为空 綁定consumer線程
- public static Condition empty = lock.newCondition();
- public static void main(String[] args) {
- List list = new ArrayList(12);
- Product product = new Product(list, 10);
- Consumer consumer = new Consumer(list, 0);
- Thread t1 = new Thread(product);
- Thread t2 = new Thread(consumer);
- t1.start();
- t2.start();
- }
- // 生产
- static class Product implements Runnable {
- private List list;
- private int maxCount;
- public Product(List list, int maxCount) {
- super();
- this.list = list;
- this.maxCount = maxCount;
- }
- @Override
- public void run() {
- while(true){
- if (lock.tryLock()) {
- try {
- if (getSize() >= maxCount) {
- System.out.println("容器已滿,product線程加入池中...");
- full.await();
- }
- System.out.println("開始生產....");
- list.add(new Object());
- //喚醒消費者線程
- empty.signal();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- } else {
- System.out.println("未获取生产资格...");
- }
- }
- }
- public int getSize() {
- return list.size();
- }
- }
- // 消费
- static class Consumer implements Runnable {
- private List list;
- private int minCount;
- public Consumer(List list, int minCount) {
- super();
- this.list = list;
- this.minCount = minCount;
- }
- @Override
- public void run() {
- while(true){
- if (lock.tryLock()) {
- try {
- if (getSize() <= minCount) {
- System.out.println("容器已空,consumer線程加入池中...");
- empty.await();
- }
- System.out.println("開始消費....");
- list.remove(0);
- //喚醒生產者線程
- full.signal();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
- } else {
- System.out.println("未获取消费资格...");
- }
- }
- }
- public int getSize() {
- return list.size();
- }
- }
- }