ReentrantLock重入锁的使用与源码分析

ReentrantLock的使用

构造方法

构造方法名说明
ReentrantLock()创建一个非公平锁
ReentrantLock(boolean fair)以给定的公平策略创建一个ReentrantLock的实例
  • 公平锁:公平锁能保证先获取锁的线程一定能先得到锁,避免饥饿,效率不是太高

  • 非公平锁:非公平锁不保证谁先获取谁先得到锁,会产生饥饿线程,效率高

实例方法

实例方法名说明
int getHoldCount()返回当前线程获取此锁的次数
Thread getOwner()返回当前拥有此锁的线程,如果不存在,则返回null
Collection getQueuedThreads()返回同步队列中等待获取此锁的线程的集合
int getQueueLength()返回同步队列中等待获此锁的线程数量
Collection getWaitingThreads(Condition condition)返回与此锁相关联的给定条件下等待的线程的集合
int getWaitQueueLength(Condition condition)返回与此锁相关联的给定条件等待的线程数
boolean hasQueuedThread(Thread thread)查询给定线程是否等待获取此锁
boolean hasQueuedThreads()查询是否有线程正在等待获取此锁。
boolean hasWaiters(Condition condition)查询是否有线程等待与此锁相关联的给定条件
boolean isFair()如果此锁的公平设置为true,则返回true
boolean isHeldByCurrentThread()查询此锁是否由当前线程持有
boolean isLocked()查询此锁被占用。
void lock()获取锁,不可中断
void lockInterruptibly()获取锁,可中断
Condition newCondition()创建与此锁相关的Condition,每调用一次创建一个
boolean tryLock()尝试获取锁
boolean tryLock(long timeout, TimeUnit unit)如果在给定的等待时间内尝试获取锁
void unlock()释放锁

ReentrantLock的使用

实现synchronized的同步功能

package com.morris.concurrent.lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo {

    private static int count = 10;

    private static Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        new A().start();
        new A().start();
        new A().start();
    }

    static class A extends Thread {
        @Override
        public void run() {
            while (true) {
                lock.lock();
                try {
                    if (0 == count) {
                        break;
                    }
                    System.out.println(count--);
                } finally {
                    lock.unlock();
                }
            }
        }
    }

}

实现wait-notify的等待-通知功能

Condition类的await()方法相当于Object类的wait()方法。

Condition类的await(long time, TimeUnit unit)方法相当于Object类的wait(long timeout)方法。

Condition类的signal()方法相当于Object类的notify()方法。

Condition类的signalAll()方法相当于Object类的notifyAll()方法。

package com.morris.concurrent.lock;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionDemo {

    private static Lock lock = new ReentrantLock();

    private static Condition condition = lock.newCondition();

    public static void main(String[] args) throws InterruptedException {
        A a = new A();
        a.start();
        Thread.sleep(1000);
        a.signal();
    }

    static class A extends Thread {
        @Override
        public void run() {
            await();
        }

        public void await() {
            lock.lock();
            try {
                try {
                    System.out.println("thread A is waiting...");
                    condition.await();
                    System.out.println("thread A is stoped");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } finally {
                lock.unlock();
            }
        }

        public void signal() {
            lock.lock();
            try {
                System.out.println("notify thread a...");
                condition.signal();
            } finally {
                lock.unlock();
            }
        }

    }

}

一个锁对应多个Condition

在多个生产者,多个消费者模型中,如果使用synchronized的wait-notify,在唤醒线程时要使用notifyAll()方法,因为有可能唤醒的是同类线程(本身是生产者线程,用notify唤醒了另一个生产者线程),会造成假死。

如果使用Lock的Condition中的await-signal,可以使用多个Condition,这样在唤醒时可以有针对的唤醒需要唤醒的线程的类型,不会造成不必要的锁的竞争。

package com.morris.concurrent.lock;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MoreConditionDemo {

    private static Lock lock = new ReentrantLock();

    private static String value;

    private static Condition conditioP = lock.newCondition();
    private static Condition conditioC = lock.newCondition();

    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            new Provider().start();
            new Consumer().start();
        }
    }

    static class Provider extends Thread {
        @Override
        public void run() {
            lock.lock();
            try {
                while (true) {
                    if (null == value) {
                        value = Thread.currentThread().getName() + " " + System.currentTimeMillis();
                        System.out.println(Thread.currentThread().getName() + " set value:" + value);
                        conditioC.signal();
                    } else {
            conditioP.await();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    static class Consumer extends Thread {
        @Override
        public void run() {
            lock.lock();
            try {
                while (true) {
                    if (null != value) {
                        System.out.println(Thread.currentThread().getName() + " get value:" + value);
                        value = null;
                        conditioP.signal();
                    } else {
                        conditioC.await();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

}

ReentrantLock重入锁源码分析

ReentrantLock重入锁,它表示该锁能够支持一个线程对资源的重复加锁。除此之外,该锁的还支持获取锁时的公平和非公平性选择。

ReentrantLock内置了一个公平锁和非公平锁。

实现可重入

重进入是指任意线程在获取到锁之后能够再次获取该锁而不会被锁所阻塞,该特性的实现需要解决以下两个问题。

  • 线程再次获取锁。锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次成功获取。

  • 锁的最终释放。线程重复n次获取了锁,随后在第n次释放该锁后,其他线程能够获取到该锁。锁的最终释放要求锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数等于0时表示锁已经成功释放。

锁的获取:

final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread(); // 当期线程
    int c = getState(); // 同步状态
    if (c == 0) {
	if (compareAndSetState(0, acquires)) {
	    setExclusiveOwnerThread(current); // 获得锁
	    return true;
	}
    }
    else if (current == getExclusiveOwnerThread()) {
	int nextc = c + acquires; // 增加获取次数
	if (nextc < 0) // overflow
	    throw new Error("Maximum lock count exceeded");
	setState(nextc);
	return true;
    }
    return false; // 没获取到锁
}

锁的释放:

protected final boolean tryRelease(int releases) {
    int c = getState() - releases; // 减去锁的次数
    if (Thread.currentThread() != getExclusiveOwnerThread())
	throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) { // 同步状态为0,则释放锁
	free = true;
	setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

实现公平

公平与非公平的区别具体体现在获取锁的过程中:

protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
	// 首先判断一下队列中是否有比当前线程等待时间更长的线程,如果有则直接进入同步队列
	if (!hasQueuedPredecessors() &&  // 公平锁加锁与非公平锁加锁就这行代码不同
	    compareAndSetState(0, acquires)) {
	    setExclusiveOwnerThread(current);
	    return true;
	}
    }
    else if (current == getExclusiveOwnerThread()) {
	int nextc = c + acquires;
	if (nextc < 0)
	    throw new Error("Maximum lock count exceeded");
	setState(nextc);
	return true;
    }
    return false;
}
}

// 判断一下队列中是否有比当前线程等待时间更长的线程
public final boolean hasQueuedPredecessors() {
	Node t = tail; // Read fields in reverse initialization order
	Node h = head;
	Node s;
	return h != t &&
	    ((s = h.next) == null || s.thread != Thread.currentThread());
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

morris131

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值