这简直就是一场没有完的玩笑,自从ByteBuffer 到底怎么用?网络编程中一点总结!发出去以后,立马引起关于变量安全的讨论,而自从发布ThreadLocal,静态变量,实例变量,局部变量的线程安全,回复:ByteBuffer 到底怎么用?网络编程中一点总结!后,就开始了关于锁的讨论。我实在是跟不上脚步了。这就是一个基础知识引发的血案啊!
关于Lock的说明,我看大家看JDK就可以了。
Lock 实现提供了比使用 synchronized
方法和语句可获得的更广泛的锁定操作。
要注意的是锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用 try-finally 或 try-catch 加以保护,以确保在必要时释放锁。
Lock
类还可以提供与隐式监视器锁完全不同的行为和语义,如保证排序、非重入用法或死锁检测。如果某个实现提供了这样特殊的语义,则该实现必须对这些语义加以记录。
注意,Lock
实例只是普通的对象,其本身可以在 synchronized
语句中作为目标使用。获取 Lock
实例的监视器锁与调用该实例的任何 lock()
方法没有特别的关系。为了避免混淆,建议除了在其自身的实现中之外,决不要以这种方式使用 Lock
实例。
除非另有说明,否则为任何参数传递 null
值都将导致抛出 NullPointerException。
我们来看一段代码和运行结果:
创建对象:
package com.entity; public class BankCard { private String cardid = "XZ456789"; private int balance = 10000; public String getCardid() { return cardid; } public void setCardid(String cardid) { this.cardid = cardid; } public int getBalance() { return balance; } public void setBalance(int balance) { this.balance = balance; } }
这个对象会被不同线程操作。
创建两个线程实现接口,一个作为儿子只消费,一个作为父亲只挣钱。可是儿子消费太快也太多,而年老的父亲挣钱慢也少。不久他们家的钱就成负数了,希望用这个例子也引发一下大家都父爱的思考吧。但是消费和存钱不能同时进行,我们在结果中可以看出。
package com.thread; import java.util.concurrent.locks.Lock; import com.entity.BankCard; /** * @说明 儿子类,只消费 */ public class Consumer implements Runnable { BankCard bc = null; Lock lock = null; Consumer(BankCard bc, Lock lock) { this.bc = bc; this.lock = lock; } public void run() { try { while(true){ lock.lock(); System.out.print("儿子要消费,现在余额:" + bc.getBalance() + "\t"); bc.setBalance(bc.getBalance() - 2000); System.out.println("儿子消费2000元,现在余额:" + bc.getBalance()); lock.unlock(); Thread.sleep(1 * 1000); } } catch (Exception e) { e.printStackTrace(); } } }
下面是另一个线程类:
package com.thread; import java.util.concurrent.locks.Lock; import com.entity.BankCard; /** * @说明 父亲类,只挣钱 */ public class Consumer2 implements Runnable { BankCard bc = null; Lock lock = null; Consumer2(BankCard bc, Lock lock) { this.bc = bc; this.lock = lock; } public void run() { try { while(true){ lock.lock(); System.out.print("父亲要存钱,现在余额:" + bc.getBalance() + "\t"); bc.setBalance(bc.getBalance() + 500); System.out.println("父亲存入500元,现在余额:" + bc.getBalance()); lock.unlock(); Thread.sleep(3 * 1000); } } catch (Exception e) { e.printStackTrace(); } } }
下面创建一个测试类,直接运行看效果:
package com.thread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import com.entity.BankCard; public class MainThread { public static void main(String[] args) { BankCard bc = new BankCard(); Lock lock = new ReentrantLock(); ExecutorService pool = Executors.newCachedThreadPool(); Consumer cm1 = new Consumer(bc, lock); Consumer2 cm2 = new Consumer2(bc, lock); pool.execute(cm1); pool.execute(cm2); } }
把锁对象传进线程,线程会使用该锁来进行对对象的锁定和解锁操作。
运行效果:
儿子要消费,现在余额:10000 儿子消费2000元,现在余额:8000 父亲要存钱,现在余额:8000 父亲存入500元,现在余额:8500 儿子要消费,现在余额:8500 儿子消费2000元,现在余额:6500 儿子要消费,现在余额:6500 儿子消费2000元,现在余额:4500 儿子要消费,现在余额:4500 儿子消费2000元,现在余额:2500 父亲要存钱,现在余额:2500 父亲存入500元,现在余额:3000 儿子要消费,现在余额:3000 儿子消费2000元,现在余额:1000 儿子要消费,现在余额:1000 儿子消费2000元,现在余额:-1000 父亲要存钱,现在余额:-1000 父亲存入500元,现在余额:-500 儿子要消费,现在余额:-500 儿子消费2000元,现在余额:-2500 儿子要消费,现在余额:-2500 儿子消费2000元,现在余额:-4500 儿子要消费,现在余额:-4500 儿子消费2000元,现在余额:-6500
我们看到,由于儿子不断的消费他们的钱很快花完了。
但是通过打印也可以发现,每次儿子或者父亲操作时,卡里面的钱是对方已经操作完的。
如果我们把一些代码注释掉:
lock.lock(); lock.unlock();
那么就没有锁概念,我们再来看一下运行结果:
儿子要消费,现在余额:10000 儿子消费2000元,现在余额:8000 父亲要存钱,现在余额:8000 父亲存入500元,现在余额:8500 儿子要消费,现在余额:8500 儿子消费2000元,现在余额:6500 儿子要消费,现在余额:6500 儿子消费2000元,现在余额:4500 儿子要消费,现在余额:4500 儿子消费2000元,现在余额:2500 父亲要存钱,现在余额:2500 父亲存入500元,现在余额:3000 儿子要消费,现在余额:3000 儿子消费2000元,现在余额:1000 儿子要消费,现在余额:1000 儿子消费2000元,现在余额:-1000 儿子要消费,现在余额:-1000 儿子消费2000元,现在余额:-3000 父亲要存钱,现在余额:-3000 父亲存入500元,现在余额:-2500 儿子要消费,现在余额:-2500 儿子消费2000元,现在余额:-4500
我想不用多说了。
如果父亲没有锁,而儿子拿走卡以后就锁定不释放,那会是什么效果呢?
儿子要消费,现在余额:10000 父亲要存钱,现在余额:10000 父亲存入500元,现在余额:8500 儿子消费2000元,现在余额:8000 儿子要消费,现在余额:8500 儿子消费2000元,现在余额:6500 儿子要消费,现在余额:6500 儿子消费2000元,现在余额:4500 父亲要存钱,现在余额:4500 父亲存入500元,现在余额:5000 儿子要消费,现在余额:4500 儿子消费2000元,现在余额:3000 儿子要消费,现在余额:3000 儿子消费2000元,现在余额:1000 儿子要消费,现在余额:1000 儿子消费2000元,现在余额:-1000 父亲要存钱,现在余额:-1000 父亲存入500元,现在余额:-500 儿子要消费,现在余额:-1000 儿子消费2000元,现在余额:-2500 儿子要消费,现在余额:-2500 儿子消费2000元,现在余额:-4500 儿子要消费,现在余额:-4500 儿子消费2000元,现在余额:-6500 父亲要存钱,现在余额:-6500 儿子要消费,现在余额:-6500 父亲存入500元,现在余额:-6000 儿子消费2000元,现在余额:-8000 儿子要消费,现在余额:-8000 儿子消费2000元,现在余额:-10000 儿子要消费,现在余额:-10000 儿子消费2000元,现在余额:-12000
我们可以看到只有儿子在消费透支了
用此来说明锁的应用和希望引起大家的一些思考,不要只写代码和每天玩了,为了你学习你的父母很辛苦,看完以后快给家里打个电话或者可以的就回家给父母做顿饭吧!
请您到ITEYE看我的原创:http://cuisuqiang.iteye.com
或支持我的个人博客,地址:http://www.javacui.com
相关推荐
在Java中,我们可以使用各种库来实现分布式锁,例如使用Jedis(Redis客户端)配合Redis的SetNX命令,或者使用Curator(Zookeeper客户端)的分布式锁功能。这些库提供了原子性的操作,保证了在分布式环境下的锁操作的...
本项目中的“springboot-redis-lock-master”可能包含了这些结构,以及启动类、配置文件、业务代码等。 7. **实战步骤**: - 配置Redis连接:在application.properties或application.yml中设置Redis的连接信息。 ...
redis-distributed-lock-demo-spring redis-distributed-lock-core 调用实例,仅供学习 基于Redisson的分布式锁spring starter实现,可用于实际项目中 redis-distributed-lock-starter调用实例 文档 springboot...
【Android LockPattern】是安卓系统中的一个开源项目,主要用于实现用户身份验证的图形解锁方式。在Android 3.2.1 beta(46)版本中,这个组件被广泛使用,为用户提供了一种安全且直观的方式来保护他们的设备。下面...
`cordova-plugin-lockpattern` 正是实现了这一功能,让用户能够在自己的 Cordova 安卓应用中轻松集成这一特性。 要使用 `cordova-plugin-lockpattern`,首先你需要确保你的开发环境已经配置好 Cordova,包括安装了...
在Java中,ReentrantLock(可重入锁)是Lock接口的主要实现,它支持公平锁和非公平锁策略。公平锁保证按照线程请求锁的顺序进行分配,而非公平锁则不保证这一点,但通常效率更高。 条件变量(Condition)是Lock的一...
此外,同步机制如synchronized关键字、volatile变量和锁(Lock)也将被详细解释。 最后,Java SE(Standard Edition)和Java EE(Enterprise Edition)的区别及应用场景也会有所提及,帮助读者理解Java在不同领域的...
在《java并发库高级应用源码--张孝祥》中,我们将会深入探讨Java中的线程管理和并发控制策略,这对于我们理解和优化多线程程序至关重要。 首先,Java中的`Thread`类是实现并发的基础,它代表了一个独立的执行线程。...
在Java高级面试中,面试官通常会关注应聘者对核心概念、高级特性和实际问题解决能力的掌握。针对“深圳-OPPO-Java高级”这个主题,我们可以预想面试会涵盖多个关键知识点,包括但不限于: 1. **Java基础**: - 类...
Java 读写锁是Java并发编程中的一种重要机制,它为多线程环境下的数据访问提供了更为精细的控制。在Java的`java.util....通过阅读和分析`readwritelock`这个示例,开发者可以更好地掌握如何在Java中使用读写锁。
本教程“springboot-distribute-lock.zip”提供了一种使用Spring Boot实现分布式锁的全面指南,涵盖了Redis、ZooKeeper、Redisson以及数据库悲观锁等多种实现方式,并结合Redis的Lua脚本进行优化。下面将详细介绍...
《Java程序员面试之--葵花宝典》是针对Java开发者面试准备的一份珍贵资料,它包含近50页的Word文档,集成了大量的热门面试问题和深入的解答,旨在帮助Java程序员在求职过程中更好地展现自己的技能和理解。...
本文将详细介绍Java中包括乐观锁、悲观锁、自旋锁、可重入锁、读写锁等多种锁机制的概念、特点、应用场景及其优化技术。 1. 乐观锁与悲观锁 乐观锁与悲观锁反映了对数据并发访问策略的不同预期。乐观锁假设数据通常...
1. ** monitors**: Java中的每个对象都有一个与之关联的监视器锁,当一个线程进入synchronized代码块或方法时,会自动获取该锁,其他线程尝试进入时会被阻塞,直到锁被释放。 2. ** 同步代码块**: 使用`synchronized...
内置锁或监视器锁(通过`synchronized`关键字实现)是Java中最基本的同步工具,但`Lock`接口提供了更多灵活性和高级特性。`Lock`接口定义了以下关键方法: - `void lock()`:获取锁。如果锁不可用,线程将阻塞直到...
描述中的 "smartapp.change-lock-code" 与标题相呼应,进一步强调了这个应用的核心功能,即更改锁的解锁密码。这可能涉及到一系列步骤,包括验证用户身份、提供新的密码选项、更新锁的内存设置,以及可能的远程操作...
本文将深入探讨C#中如何使用Lock和Redis分布式锁来解决并发问题,以秒杀系统为例进行阐述。 首先,让我们理解什么是并发控制。并发控制是指在多线程环境下确保数据的一致性和完整性,防止多个线程同时访问同一资源...
源码文件"V9最新门锁接口函数例程_门锁_接口_V9-lock_v9_v9门锁_源码.rar"很可能包含了实现这些功能的C/C++或Java代码,以及可能的示例程序或测试脚本,帮助开发者快速理解和集成这些接口。在实际开发中,开发者需要...
首先,Java中的锁主要包括两种类型:内置锁(也称为监视器锁)和显式锁。内置锁是通过`synchronized`关键字实现的,它隐含地在每个对象上都存在。当一个线程进入一个由`synchronized`修饰的方法或代码块时,会自动...