并发编程学习总结(四) :java 显式锁ReentrantLock使用详解之lock()\unlock() 加锁与释放锁
来源:互联网 发布:苗木花卉识别软件 编辑:程序博客网 时间:2024/05/29 15:21
在大多数实际的多线程应用中,两个或两个以上的线程需要共享对同一数据的存取。如果两个线程存取相同的对象,并且每一个线程都调用了一个修改该对象状态的方法,那么线程彼此踩了对方的脚,根据各线程访问数据的次序,可能会产生讹误的对象。这样的一种现象称之为竞争条件。
当然多个线程共享一个变量在实际的应用中有时难以避免,但是我们可以通过java提供的一些技术来避免线程彼此踩脚的行为发生。
java提供了锁机制来对多个线程共享一个变量进行同步,在java SE 5.0引入了显式锁ReentrantLock类,以及从1.0版本开始的对象内部锁 可以通过synchronized关键字声明某个线程持有这个对象内部锁,我们这小结先学习ReentrantLock锁的使用,下一节学习synchronized关键字的使用。
(1) ReentrantLock锁的使用结构
ReentrantLock 是java.unti.concurrent包下的一个类,它的一般使用结构如下所示:
public void lockMethod() {ReentrantLock myLock = new ReentrantLock();myLock.lock();try{// 受保护的代码段//critical section} finally {// 可以保证发生异常 锁可以得到释放 避免死锁的发生myLock.unlock();}}
把解锁操作括在finally字句之内是至关重要的,如果受保护的代码抛出异常,锁可以得到释放,这样可以避免死锁的发生
我们执行下面代码:
public class ReentrantLockTest1 {private int num = 10; private ReentrantLock myLock = new ReentrantLock();public void writeNumMethod() {//myLock.lock();try{// 受保护的代码段int index =10;while(index > 0) {System.out.println(Thread.currentThread().getName() + " : "+ num);num-=10;long beginTime = System.currentTimeMillis();while(System.currentTimeMillis() - beginTime < 10){}num+=10;System.out.println(Thread.currentThread().getName() + " : "+ num);index--;}} finally {// 可以保证发生异常 锁可以得到释放 避免死锁的发生//myLock.unlock();}}public void readNumMethod() {//myLock.lock();try{int index = 10;// 受保护的代码段while(index > 0) {System.out.println(Thread.currentThread().getName() + " : "+ num);index--;}} finally {// 可以保证发生异常 锁可以得到释放 避免死锁的发生//myLock.unlock();}}public static void main(String [] args) {final ReentrantLockTest1 myLockTest = new ReentrantLockTest1();Thread t1 = new Thread(new Runnable() {public void run() {myLockTest.writeNumMethod();}},"A");Thread t2 = new Thread(new Runnable() {public void run() {myLockTest.readNumMethod();}},"B");t1.start();t2.start();}}
上面示例中 writeNumMethod方法 对num变量进行先减10 然后再加10,readNumMethod方法读取num的值,线程A执行writeNumMethod方法,线程B执行readNumMethos方法,我们期望两个线程的 输出的结果都是10,但是由于我们没有对这个共享变量num 进行同步,假如此时线程A执行到num-=10这句代码时,线程的cpu时间片到时了,这时操作系统就会去调度线程B这样线程B就会输出0值。我们看一输出结果。
输出结果:
A : 10B : 10B : 0B : 0B : 0B : 0B : 0B : 0B : 0B : 0B : 0A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10
果然共享变量出现了讹误的现象。
那么如果我们取消代码中显式锁前的注释,再次运行代码。
A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10A : 10B : 10B : 10B : 10B : 10B : 10B : 10B : 10B : 10B : 10B : 10
输出结果是显式锁很好的保护了 writeNumMethod 的操作,假设线程A在执行结束前被剥夺了运行权,这是线程B调用readNumMethod方法去读取num的值,但是由于线程B不能获得锁,线程B必须等待线程A释放锁才能执行readNumMethod方法。这样就保证了writeNumMethod方法的原子性,也就保证了共享变量num不会出现讹误的现象。
(2)ReentrantLock是可重入锁
ReentrantLock持有一个所计数器,当已持有所的线程再次获得该锁时计数器值加1,每调用一次lock.unlock()时所计数器值减一,直到所计数器值为0,此时线程释放锁。
我们测试以下代码:
public class ReentrantLockTest2 {private ReentrantLock lock = new ReentrantLock();public void testReentrantLock() {// 线程获得锁lock.lock();try {System.out.println(Thread.currentThread().getName() + " get lock");long beginTime = System.currentTimeMillis();while(System.currentTimeMillis() - beginTime < 100){}lock.lock();try {System.out.println(Thread.currentThread().getName() + " get lock again");long beginTime2 = System.currentTimeMillis();while(System.currentTimeMillis() - beginTime2 < 100){}}finally {// 线程释放锁lock.unlock();System.out.println(Thread.currentThread().getName() + " release lock");}} finally {// 线程释放锁lock.unlock();System.out.println(Thread.currentThread().getName() + " release lock again");}}public static void main(String[] args) {// TODO Auto-generated method stubfinal ReentrantLockTest2 test2 = new ReentrantLockTest2();Thread thread = new Thread(new Runnable(){public void run() {test2.testReentrantLock();}},"A");thread.start();}}输出结果:A get lockA get lock againA release lockA release lock again
- 并发编程学习总结(四) :java 显式锁ReentrantLock使用详解之lock()\unlock() 加锁与释放锁
- 并发编程学习总结(六) :java 显式锁ReentrantLock使用详解之测试锁与超时
- ReentrantLock使用详解(1)之lock/unlock
- 并发编程学习总结(五) :java 显式锁ReentrantLock使用详解之条件对象(2)
- Java并发编程札记-(四)JUC锁-02Lock与ReentrantLock
- 《深入浅出 Java Concurrency》—锁机制(四) 锁释放与条件变量 (Lock.unlock And Condition)
- 《深入浅出 Java Concurrency》—锁机制(四) 锁释放与条件变量 (Lock.unlock And Condition)
- 《Java源码分析》:ReentrantLock.unlock 释放锁
- 《Java源码分析》:ReentrantLock.unlock 释放锁
- Java并发编程 之 Condition与ReentrantLock的使用
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之三unlock方法分析
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之三unlock方法分析
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之三unlock方法分析
- ReentrantLock源码之二unlock方法解析(锁的释放)
- JAVA并发编程学习笔记之ReentrantLock
- JAVA并发编程学习笔记之ReentrantLock
- java 并发编程学习之三 ---- ReentrantLock
- jdk源码解读-并发包-Lock-ReentrantLock(1)--lock()与unlock()方法走读
- Android Handler(子线程Handler)异步消息处理机制的妙用(活用信号量) 创建强大的图片加载类
- android静音播放视频
- Dhroid框架六大组件之Ioc容器【上】
- unity游戏优化
- POJ 3347 Kadj Squares(计算几何)
- 并发编程学习总结(四) :java 显式锁ReentrantLock使用详解之lock()\unlock() 加锁与释放锁
- PPT如何带走常用的字体
- Easy Digital Downloads插件拓展 Frontend Submissions 前端提交多用户插件[更新至 v2.4.1]
- 搭建一个私有Registry(加强版想做没做成功,楼主不会,真心求教!!!)
- C# 转换时间戳
- 父窗口打开子窗口,子窗口关闭后自动刷新父窗口
- 三层项目
- Quartz2d 画图
- LeetCode- 238. Product of Array Except Self