博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java并发编程 - 显示锁Lock和ReentrantLock
阅读量:7210 次
发布时间:2019-06-29

本文共 3974 字,大约阅读时间需要 13 分钟。

hot3.png

Lock

Lock是一个接口,提供了无条件的、可轮询的、定时的、可中断的锁获取操作,所有加锁和解锁的方法都是显式的。包路径是:java.util.concurrent.locks.Lock。核心方法有 lock()unlock()tryLock(),实现类有 ReentrantLockReentrantReadWriteLock.ReadLockReentrantReadWriteLock.WriteLock

** 方法及说明 **

public abstract interface Lock {	// 获取锁。如果锁不可用,出于线程调度目的,将禁用当前线程,并且在获得锁之前,	// 该线程将一直处于休眠状态	void lock();	// 如果当前线程未被中断,则获取锁。如果锁可用,则获取锁,并立即返回。	// 如果锁不可用,出于线程调度目的,将禁用当前线程,并且在发生以下两种情况之一以前,该线程将一直处于休眠状态:	// 锁由当前线程获得;或者其他某个线程中断当前线程,并且支持对锁获取的中断。	// 如果当前线程:在进入此方法时已经设置了该线程的中断状态;	// 或者在获取锁时被中断,并且支持对锁获取的中断,则将抛出`InterruptedException`,并清除当前线程的已中断状态	void lockInterruptibly() throws InterruptedException;	// 仅在调用时锁为空闲状态才获取该锁。如果锁可用,则获取锁,并立即返回值 true。	// 如果锁不可用,则此方法将立即返回值 false。通常对于那些不是必须获取锁的操作可能有用	boolean tryLock();	// 如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。	// 如果锁可用,则此方法将立即返回值 true。如果锁不可用,出于线程调度目的,	// 将禁用当前线程,并且在发生以下三种情况之一前,该线程将一直处于休眠状态	boolean tryLock(long time, TimeUnit unit) throws InterruptedException;	// 释放锁。对应于 lock()、tryLock()、tryLock(time, unit)、lockInterruptibly() 等操作,	// 如果成功的话应该对应着一个`unlock()`,这样可以避免死锁或者资源浪费	void unlock();	// 返回用来与此 Lock 实例一起使用的 Condition 实例	Condition newCondition();}

ReentrantLock

ReentrantLock是Lock的实现类,是一个互斥的同步器,它具有扩展的能力。在竞争条件下,ReentrantLock 的实现要比现在的 synchronized 实现更具有可伸缩性。(有可能在 JVM 的将来版本中改进 synchronized 的竞争性能)这意味着当许多线程都竞争相同锁定时,使用 ReentrantLock 的吞吐量通常要比 synchronized 好。换句话说,当许多线程试图访问 ReentrantLock 保护的共享资源时,JVM 将花费较少的时间来调度线程,而用更多个时间执行线程。虽然 ReentrantLock 类有许多优点,但是与同步相比,它有一个主要缺点 — 它可能忘记释放锁定。ReentrantLock是在工作中对方法块加锁使用频率最高的。

** 使用方法如下: **

class X {	private final ReentrantLock lock = new ReentrantLock();	// …	public void m() {		lock.lock(); // 获得锁		try {			// … 方法体		} finally {			lock.unlock();//解锁		}	}}

** Lock与synchronized 的比较: **

  1. Lock使用起来比较灵活,但是必须有释放锁的动作;
  2. Lock必须手动释放和开启锁,synchronized 不需要;
  3. Lock只适用与代码块锁,而synchronized 对象之间的互斥关系;

示例

请注意以下两种方式的区别:

第一种方式:两个方法之间的锁是独立的

public class ReentrantLockDemo {	public static void main(String[] args) {		final Count ct = new Count();		for (int i = 0; i < 2; i++) {			new Thread() {				public void run() {					ct.get();				}			}.start();		}		for (int i = 0; i < 2; i++) {			new Thread() {				public void run() {					ct.put();				}			}.start();		}	}}class Count {	public void get() {		final ReentrantLock lock = new ReentrantLock();		try {			lock.lock(); // 加锁			System.out.println(Thread.currentThread().getName() + " get begin");			Thread.sleep(1000);// 模仿干活			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(1000);// 模仿干活			System.out.println(Thread.currentThread().getName() + " put end");			lock.unlock(); // 解锁		} catch (InterruptedException e) {			e.printStackTrace();		}	}}

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

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

第二种方式,两个方法之间使用相同的锁

ReentrantLockDemo 类的内容不变,将Count中的ReentrantLock改成全局变量,如下所示:

class Count {	final ReentrantLock lock = new ReentrantLock();	public void get() {		try {			lock.lock(); // 加锁			System.out.println(Thread.currentThread().getName() + " get begin");			Thread.sleep(1000);// 模仿干活			System.out.println(Thread.currentThread().getName() + " get end");			lock.unlock(); // 解锁		} catch (InterruptedException e) {			e.printStackTrace();		}	}	public void put() {		try {			lock.lock(); // 加锁			System.out.println(Thread.currentThread().getName() + " put begin");			Thread.sleep(1000);// 模仿干活			System.out.println(Thread.currentThread().getName() + " put end");			lock.unlock(); // 解锁		} catch (InterruptedException e) {			e.printStackTrace();		}	}}

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

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

转载于:https://my.oschina.net/u/215547/blog/809379

你可能感兴趣的文章
009——数组(九) each list array_map array_walk array_walk_recursive
查看>>
用shell脚本增加几个组,并在每个组里创建一定的用户
查看>>
导包路径方法
查看>>
20061218: 多个任务管理器
查看>>
WCF 可靠会话
查看>>
vim+makefile入门编辑,编译,差错实例
查看>>
Python之基础练习题
查看>>
AC日记——回文子串 openjudge 1.7 34
查看>>
易买网总结
查看>>
C#导入Excel报错问题。
查看>>
网站前端性能优化
查看>>
课后作业
查看>>
51nod 1265 四点共面【计算几何+线性代数】
查看>>
VMware在宿主上没有VMnet0、VMnet8,解决方法
查看>>
BCP SQL导出EXCEL常见问题及解决方法;数据导出存储过程
查看>>
C#反射学习
查看>>
实验二 直线DDA生成算法的GDI实现
查看>>
常用linux指令
查看>>
selenium之调用js解决淘宝点击下一页问题(JAVA版)
查看>>
flask安装及第一个程序
查看>>