ReentrantLock类
ReentrantLock类能达到synchronized关键字的效果,且它的扩展功能更多。
lock()方法与unlock()方法
通过ReentrantLock对象lock()方法获得锁,unlock()方法释放锁。
public class myTask {
private Lock lock = new ReentrantLock();
public void testMethod() {
lock.lock();
for(int i = 0; i < 5; i++) {
System.out.println("线程:" + Thread.currentThread().getName());
}
lock.unlock();
}
}
public class myThread extends Thread {
private myTask task;
public myThread(myTask task) {
this.task = task;
}
@Override
public void run() {
task.testMethod();
}
}
public class Run {
public static void main(String[] args) {
myTask task = new myTask();
myThread a1 = new myThread(task);
myThread a2 = new myThread(task);
myThread a3 = new myThread(task);
a1.start(); a2.start(); a3.start();
}
}
Condition实现等待/通知
借助Condition对象,ReentrantLock类可以实现等待/通知。在一个Lock对象里,可以创建多个Condition实例。
public class myTask {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void await() {
try {
lock.lock();
System.out.println("等待时间为:" + System.currentTimeMillis());
condition.await();
}catch (InterruptedException e ){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void signal() {
try {
lock.lock();
System.out.println("通知时间为:" + System.currentTimeMillis());
condition.signal();
System.out.println("B");
}finally {
lock.unlock();
}
}
}
public class ThreadA extends Thread {
private myTask task;
public ThreadA(myTask task) {
this.task = task;
}
@Override
public void run() {
task.await();
}
}
public class Run {
public static void main(String[] args) throws InterruptedException{
myTask task = new myTask();
ThreadA a1 = new ThreadA(task);
Thread.sleep(3000);
task.signal();
a1.start();
}
}
与notify()/notifyAll()方法相比,可以通过使用多个Condition实现”选择性通知“。
public class myTask {
private Lock lock = new ReentrantLock();
private Condition conditionA = lock.newCondition();
private Condition conditionB = lock.newCondition();
public void awaitA() {
try {
lock.lock();
System.out.println("A等待时间为:" + System.currentTimeMillis());
conditionA.await();
}catch (InterruptedException e ){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void awaitB() {
try {
lock.lock();
System.out.println("B等待时间为:" + System.currentTimeMillis());
conditionB.await();
}catch (InterruptedException e ){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void signalB() {
try {
lock.lock();
System.out.println("B通知时间为:" + System.currentTimeMillis());
conditionB.signalAll();
}finally {
lock.unlock();
}
}
public void signalA() {
try {
lock.lock();
System.out.println("A通知时间为:" + System.currentTimeMillis());
conditionA.signalAll();
}finally {
lock.unlock();
}
}
}
public class ThreadA extends Thread {
private myTask task;
public ThreadA(myTask task) {
this.task = task;
}
@Override
public void run() {
task.awaitA();
}
}
public class ThreadB extends Thread {
private myTask task;
public ThreadB(myTask task) {
this.task = task;
}
@Override
public void run() {
task.awaitB();
}
}
public class Run {
public static void main(String[] args) throws InterruptedException{
myTask task = new myTask();
ThreadA ta = new ThreadA(task);
ThreadB tb = new ThreadB(task);
ta.start(); tb.start();
Thread.sleep(3000);
task.signalA();
}
}
输出:

生产者/消费者模式:多对多
public class myTask {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private boolean hasValue = false;
public void setValue() {
try {
lock.lock();
while(hasValue == true) {
System.out.println("生产者进入睡眠");
condition.await();
}
System.out.println("打印");
hasValue = true;
condition.signalAll();
}catch (InterruptedException e ){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void getValue() {
try {
lock.lock();
while(hasValue == false) {
System.out.println("消费者进入睡眠");
condition.await();
}
System.out.println("消费");
hasValue = false;
condition.signalAll();
}catch (InterruptedException e ){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
public class ThreadA extends Thread {
private myTask task;
public ThreadA(myTask task) {
this.task = task;
}
@Override
public void run() {
task.setValue();
}
}
public class ThreadB extends Thread {
private myTask task;
public ThreadB(myTask task) {
this.task = task;
}
@Override
public void run() {
task.getValue();
}
}
public class Run {
public static void main(String[] args) throws InterruptedException{
myTask task = new myTask();
ThreadA[] ta = new ThreadA[10];
ThreadB[] tb = new ThreadB[10];
for(int i = 0; i < 10; i++) {
ta[i] = new ThreadA(task);
tb[i] = new ThreadB(task);
ta[i].start(); tb[i].start();
}
}
}
公平锁与非公平锁
锁Lock分为公平锁和非公平锁,公平锁即先来先得的顺序;而非公平锁则是随机的,可能造成某些线程一直拿不到锁。
默认情况下,ReentrantLock类使用的是非公平锁。
Lock lock = new ReentrantLock(true);
//false 为非公平
先运行的线程先拿到锁。

非公平锁

相关方法
int getHoldCount()
是查询当前线程保存锁定的个数
ReentrantLock lock = new ReentrantLock();
lock.getHoldCount();
int getQueueLength()
返回正等待获取此锁定的线程估计数。比如有5个线程,1个线程执行了await()方法,则在调用该方法返回的是4,即有4个线程同时等待lock的释放。
ReentrantLock lock = new ReentrantLock();
lock.getQueueLength()
int getWaitQueueLength(Condition condition)
返回等待与Condition相关的线程估计数。比如有5个线程都执行了同一Condition对象的await()方法,则其方法返回5。
ReentrantLock lock = new ReentrantLock();
lock.getWaitQueueLength(condition)
boolean hasQueuedThread(Thread thread)
查询指定的线程是否正等待获取此锁。
ReentrantLock lock = new ReentrantLock();
lock.hasQueuedThread();
而boolean hasQueuedThreads() 则是查询是否有线程正在等待获取锁
boolean hasWaiters(Condition condition)
查询是否有线程正在等待与这个锁相关的condition条件
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.hasWaiters(condition);
boolean is Fair()
判断是否为公平锁
boolean isHeldByCurrentThread()
查询当前线程是否是否已上锁
System.out.println(lock.isHeldByCurrentThread()); //false
lock.lock();
System.out.println(lock.isHeldByCurrentThread()); //true
boolean isLocked()
查询此锁是否由任意一个线程保持
System.out.println(lock.isLocked()); //false
lock.lock();
System.out.println(lock.isLocked()); //true
void lockInterruptibly()
若当前线程未被中断,则获取此锁;若中断则出现异常。
一个线程在上锁时,如果用的是lock()方法,那么当它被中断时,该线程不会出现异常;如果是lockInterruptibly(),则会抛出InterrupterException异常。
boolean tryLock()
当该方法被调用时,若该锁没被其他线程拿到,则该所被当前线程获取。
if(lock.tryLock()) {
System.out.println(Thread.currentThread().getName() + "拿到锁");
}else {
System.out.println(Thread.currentThread().getName() + "没有拿到锁");
}
boolean tryLock(long timeout, TimeUnit unit)
若该锁在给定时间内没被其他线程拿到,且当前线程x未被中断,则x拿到锁。
if(lock.tryLock(3, TimeUnit.SECONDS)) {
System.out.println(Thread.currentThread().getName() + "拿到锁");
}else {
System.out.println(Thread.currentThread().getName() + "没有拿到锁");
}
void awaitUninterruptibly()
该方法与await()大致相同。当线程在lock()后,进入await()后,若此时线程被interrupt(),则会抛出异常;而awaitUninterruptibly()则不会响应异常。
condition.await();
condition.awaitUninterruptibly();
boolean awaitUntil(Date deadline)
线程在Date 时间内等待。
public class myTask {
public ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void waitMethod() {
try {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, 10); // 设置等待时间10s
lock.lock();
System.out.println("开始等待:" +System.currentTimeMillis());
condition.awaitUntil(calendar.getTime());
System.out.println("结束等待:" +System.currentTimeMillis());
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void notifyMethod() {
try {
lock.lock();
System.out.println("开始通知:" +System.currentTimeMillis());
condition.signalAll();
System.out.println("结束通知:" +System.currentTimeMillis());
}finally {
lock.unlock();
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException{
myTask task = new myTask();
Runnable waitRun = new Runnable() {
@Override
public void run() {
task.waitMethod();;
}
};
Runnable notifyRun = new Runnable() {
@Override
public void run() {
task.notifyMethod();
}
};
Thread waitThread = new Thread(waitRun);
waitThread.start();
// Thread.sleep(2000);
// Thread notifyThread = new Thread(notifyRun);
// notifyThread.start();
}
}
输出:

线程在10后唤醒。取消掉三行的注释,则输出为:

可以发现,在等待时间到达前,可以被其他线程提前唤醒。
使用Condition实现顺序执行
通过condition对象可以线程执行的任务进行排序规划
public class Run {
volatile private static int nextTaskNum = 1;
private static ReentrantLock lock = new ReentrantLock();
private static Condition conditionA = lock.newCondition();
private static Condition conditionB = lock.newCondition();
private static Condition conditionC = lock.newCondition();
public static void main(String[] args) throws InterruptedException{
Thread threadA = new Thread() {
@Override
public void run() {
try {
lock.lock();
while(nextTaskNum != 1) {
conditionA.await();
}
for(int i = 0; i < 3; i++) {
System.out.println("A:" + i);
}
nextTaskNum = 2;
conditionB.signalAll();
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
};
Thread threadB = new Thread() {
@Override
public void run() {
try {
lock.lock();
while(nextTaskNum != 2) {
conditionB.await();
}
for(int i = 0; i < 3; i++) {
System.out.println("B:" + i);
}
nextTaskNum = 3;
conditionC.signalAll();
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
};
Thread threadC = new Thread() {
@Override
public void run() {
try {
lock.lock();
while(nextTaskNum != 3) {
conditionC.await();
}
for(int i = 0; i < 3; i++) {
System.out.println("C:" + i);
}
nextTaskNum = 1;
conditionA.signalAll();
}catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
};
Thread[] aArray = new Thread[5];
Thread[] bArray = new Thread[5];
Thread[] cArray = new Thread[5];
for(int i = 0; i < 5; i++) {
aArray[i] = new Thread(threadA);
bArray[i] = new Thread(threadB);
cArray[i] = new Thread(threadC);
aArray[i].start();
bArray[i].start();
cArray[i].start();
}
}
}
ReentrantReadWriteLock类
ReentrantLock保证了同一时间内只有一个线程在执行lock()后面的任务,这样虽然保证的变量的线程安全性,但效率低下。而ReentrantReadWriteLock类可以加快运行效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁ReentrantReadWriteLock来提升运行速度。
读写锁有两个锁:读操作相关的锁,也叫共享锁;另一个是写操作相关的锁,也叫排他锁。多个读锁不互斥,即进行读操作的多个线程都可以获取读锁;读锁与写锁互斥,即同一时刻只允许一个线程进行写操作。
运行下面代码,可以发现两个线程几乎同时进入lock()后面的代码。
public class myTask {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void read() {
try {
try {
lock.readLock().lock(); // 写锁为: lock.writeLock().lock()
System.out.println(Thread.currentThread().getName() +" 获得读锁,时间:" +System.currentTimeMillis());
Thread.sleep(10000);
}finally {
lock.readLock().unlock(); // 写锁为: lock.writeLock().unlock()
}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
public void write() {
try {
try {
lock.writeLock().lock()
System.out.println(Thread.currentThread().getName() +" 获得写锁,时间:" +System.currentTimeMillis());
Thread.sleep(10000);
}finally {
lock.writeLock().unlock()
}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ThreadA extends Thread {
private myTask task;
public ThreadA(myTask task) {
this.task = task;
}
@Override
public void run() {
task.read();
}
}
public class Run {
public static void main(String[] args) {
myTask task = new myTask();
ThreadA ta = new ThreadA(task);
ta.setName("ta");
ThreadB tb = new ThreadB(task);
tb.setName("tb");
ta.start(); tb.start();
}
}
public class ThreadB extends Thread {
private ReadWriteLock.myTask task;
public ThreadB(myTask task) {
this.task = task;
}
@Override
public void run() {
task.read();
}
}
5万+

被折叠的 条评论
为什么被折叠?



