ReentrantLock的分析

1.ReentrantLock的源码简单解读

/*
 * ReentrantLock是轻量级锁
 * 非公平锁即不检查是否为阻塞队列头成员,直接让到达的程序进行锁定
 * 公平锁会进行队列检查确保不抢占
 * ----
 * 如果没有竞争状态,并发只是交替执行,如果线程竞争,则会调用阻塞队列来控制线程
 * ----
 * 面对抢占性的其它线程,源码并没有对同时占到的线程进行回滚,但没有出现问题应该是其它底层控制对其进行了回滚
 * ----
 * reentrantLock是允许同个线程的重入的,源码有currentThread == newThread?的判断
 * ----
 * 对于阻塞队列,在被使用时才进行初始化,head初始化为threadNull作为第一个节点,第一个线程节点Node入队,为队列链表的第二个节点(head一直作为threadNull)
 * 完成入队操作,判断node.ahead==head?不是,直接park()。如果是,自旋一次,对lock进行acquire操作,若失败则修改上一个节点waitState为-1,再自旋一次
 * 如果还是没有得到lock,则进行park操作
 * 关于修改上一个节点waitState代表自身阻塞状态
 * 一是若阻塞了不能操作,若先修改如果park失败但自身waitState修改了会异常。二是解锁过程中,是调用头节点waitState判断是否对第二个节点进行unPark
 * 所以自身的waitState是代表下一个,当head偏移到最后一个(将最后一个等待unPark并threadNull),下次直接判断waitState==0,不进行唤醒操作即可
 * ----
 * 总结:是否竞争 --> 是否排队(初始化判断、队头判断) --> {自旋+park()+CAS},在队头判断里,注意h!=t&&((s=h.next)==null||s.thread!=Thread.currentThread())
 * ----
 * 在lock代码有打断处理代码,但代码设计为不执行。因为与lockInterruptibly(允许打断)都调用parkAndCheckInterrupt(),代码达到统一
 * 如果是打断的话,是自我打断,使得被自我打断的线程跳到catch异常处理中去,但是并不会干扰原先进程的运行,所以如果要访问共享资源的话还是要进行锁的排队,不过也可以不访问共享资源,破除死锁
 * */

2.对ReentrantLock的测试 

普通lock的测试:

import java.util.concurrent.locks.ReentrantLock;

public class rlockThread implements Runnable {
	ReentrantLock lock;
	int serverTime = 0;

	public rlockThread(boolean fair) {
		// 无参默认非公平锁,true是公平锁
		lock = new ReentrantLock(fair);
	}

	@Override
	public void run() {
		try {
			lock.lock();
			serverTime += 10;
			Thread.sleep(1000);
			System.out.println(Thread.currentThread().getName() + " have server util: " + serverTime);
		} catch (Exception e) {
			System.out.println(Thread.currentThread().getName() + "Thread wrong!");
		} finally {
			lock.unlock();
		}
	}
}

结果:(注:由于线程的机器启动上有一定的时差,所以可能会让先start()的Thread反而晚启动。)

公平锁:

非公平锁:

可打断的lock:

import java.util.concurrent.locks.ReentrantLock;

public class rIntpLock implements Runnable {
	ReentrantLock lock;
	int serverTime = 0;

	public rIntpLock(boolean fair) {
		// 无参默认非公平锁,true是公平锁
		lock = new ReentrantLock(fair);
	}

	@Override
	public void run() {
		try {
			lock.lockInterruptibly();
			System.out.println(Thread.currentThread().getName() + " get the lock!");
			Thread.sleep(1000);
			serverTime += 10;
			System.out.println(Thread.currentThread().getName() + " have server util: " + serverTime);
		} catch (InterruptedException e1) {
			// 打断异常处理
			System.out.println(Thread.currentThread().getName() + " is jump to excetion!");
			try {
				// lock.lockInterruptibly();
				Thread.sleep(3000);
				serverTime += 10;
				System.out.println(Thread.currentThread().getName() + " have server util: " + serverTime);
			} catch (InterruptedException e) {
				System.out.println(e);
			}

		} finally {
			lock.unlock();
		}
	}
}

结果:

3.await和signal的应用

手动阻塞调度:利用reentrantlock的condition的await()和signal()可以进行定向的阻塞队列管理,await即阻塞、释放锁,signal即唤醒线程,占有锁。(signalAll()在主控制上较为常用)

示例:(模拟资源的增加与获取)

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

public class RAwaitAndSignal implements Runnable {
	private ReentrantLock lock = new ReentrantLock();
	private int source = 0;
	private Condition full = lock.newCondition();
	private Condition empty = lock.newCondition();

	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			try {
				offer();
				Thread.sleep(1000);
				require();
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public void offer() throws InterruptedException {
		lock.lock();
		try {
			if (source >= 10)
				full.await();
			source++;
			System.out.println(Thread.currentThread().getName() + ":+1=" + source);
			empty.signal();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public void require() throws InterruptedException {
		lock.lock();
		try {
			if (source == 0)
				empty.await();
			source--;
			System.out.println(Thread.currentThread().getName() + ":-1=" + source);
			full.signal();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
}

 


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值