Java多线程程序非阻塞式锁定实现
2012-06-19 14:22
344 查看
Java对多线程程序的锁定已经有良好的支持,通常使用synchronized修饰一个方法或者一段代码。但是有一个问题,多个线程同时调用同一个方法的时候,所有线程都被排队处理了。该被调用的方法越耗时,线程越多的时候,等待的线程等待的时间也就越长,甚至于几分钟或者几十分钟。对于Web等对反应时间要求很高的系统来说,这是不可以接受的。本文就介绍一种自己实现的锁定方法,可以在没有拿到锁之后马上返回,告诉客户稍后重试。
某一段程序同一时刻需要保证只能单线程调用,那么策略很简单,最先到的线程获取锁成功,在它释放之前其它线程都会获取失败。首先要构造一个全局的系统锁仓库,代码如下:
锁仓库提供了三个方法,都是静态的,可以在系统内任意地方调用。 这里要提的是锁名,是一个字符串,可以随意构造,通常是需要锁定的方法名+需要单线程处理的标识。比如部门ID。这样不同的部门有不同的锁,独立运行,同一个部门同一个锁,单线程处理。具体使用如下:
通过以上设计,系统内部任何耗时且需要保证单线程的地方都可以用该方法实现非阻塞式的访问,提高用户体验。甚至于有的调用本身就要求这样的设计,只需处理一次,比如做日终。锁名的自定义带来了锁粒度的灵活设定,可以在运行时根据参数实现任意级别的锁定。
某一段程序同一时刻需要保证只能单线程调用,那么策略很简单,最先到的线程获取锁成功,在它释放之前其它线程都会获取失败。首先要构造一个全局的系统锁仓库,代码如下:
/* * LockStore.java 2012-5-15 */ import java.util.Date; import java.util.HashMap; import java.util.Map; /** * 公用的内存锁仓库. 分为获取锁和释放锁两种操作。 * * @version 1.0 */ public final class LockStore { // volatile保证所有线程看到的锁相同 private static volatile Map<String, Date> locks = new HashMap<String, Date>(); private LockStore() { } /** * 根据锁名获取锁 * * @param lockName * 锁名 * @return 是否锁定成功 */ public synchronized static Boolean getLock(String lockName) { Boolean locked = false; if (StringUtils.isEmpty(lockName)) { throw new RuntimeException("Lock name can't be empty"); } Date lockDate = locks.get(lockName); if (lockDate == null) { locks.put(lockName, new Date()); locked = true; } return locked; } /** * 根据锁名释放锁 * * @param lockName * 锁名 */ public synchronized static void releaseLock(String lockName) { if (StringUtils.isEmpty(lockName)) { throw new RuntimeException("Lock name can't be empty"); } Date lockDate = locks.get(lockName); if (lockDate != null) { locks.remove(lockName); } } /** * 获取上次成功锁定的时间 * * @param lockName * 锁名 * @return 如果还没有锁定返回NULL */ public synchronized static Date getLockDate(String lockName) { if (StringUtils.isEmpty(lockName)) { throw new RuntimeException("Lock name can't be empty"); } Date lockDate = locks.get(lockName); return lockDate; } }
锁仓库提供了三个方法,都是静态的,可以在系统内任意地方调用。 这里要提的是锁名,是一个字符串,可以随意构造,通常是需要锁定的方法名+需要单线程处理的标识。比如部门ID。这样不同的部门有不同的锁,独立运行,同一个部门同一个锁,单线程处理。具体使用如下:
/* * LockTest.java 2012-6-19 */ import java.text.SimpleDateFormat; import java.util.Date; /** * 锁仓库的使用 * * @version 1.0 */ public class LockTest { public Boolean doSomething(String departmentId, StringBuffer message) { // 同一个部门同时只能有一个处理, 不同部门可以并行处理 String lockName = "doSomething_" + departmentId; Boolean result; if (LockStore.getLock(lockName)) { try { // do things here } finally { LockStore.releaseLock(lockName); result = true; } } else { Date lastLockDate = LockStore.getLockDate(lockName); String messageStr = "您所在的部门已经在处理中, 启动时间为:" + getDateDetailDesc(lastLockDate); message.append(messageStr); result = false; } return result; } /* * 获取日期的具体时间描述 */ private String getDateDetailDesc(Date date) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); return sdf.format(date); } }
通过以上设计,系统内部任何耗时且需要保证单线程的地方都可以用该方法实现非阻塞式的访问,提高用户体验。甚至于有的调用本身就要求这样的设计,只需处理一次,比如做日终。锁名的自定义带来了锁粒度的灵活设定,可以在运行时根据参数实现任意级别的锁定。
相关文章推荐
- 用多线程实现的Java爬虫程序2
- Java 多线程 爬虫程序(spider)设计与实现
- 多线程实现的Java爬虫程序
- java登录程序用户密码5分钟内输错3次锁定用户账号一天的实现
- Java多线程实现简单的售票程序
- java登录程序用户密码5分钟内输错3次锁定用户账号一天的实现
- 用Java实现的多线程扫描IP程序
- 用多线程实现的Java爬虫程序
- Android(java)学习笔记75:匿名内部类的方式实现多线程程序
- Java多线程实现扑克牌发牌程序实例
- Java多线程实现快速切分文件的程序
- JAVA基础再回首(二十四)——多线程的概述、实现方式、线程控制、生命周期、多线程程序练习、安全问题的解决
- Java多线程实现生产者消费者程序(Wait,Notify实现和Lock,Condition实现)
- 如何通过java程序来实现多线程的程序呢?
- Java - 编写多线程程序有几种实现方式?
- 黑马程序员-JAVA学习之用多线程实现简单UDP聊天程序
- java多线程实现卖票程序(synchronized)
- 网易2015编程题(一用Java实现一个多线程程序将这个10000个数输出到5个不用文件中)
- Java多线程实现简单的售票程序
- java基础--24.多线程的应用--电影院卖票程序的实现