Java多线程程序非阻塞式锁定实现

简介:

Java对多线程程序的锁定已经有良好的支持,通常使用synchronized修饰一个方法或者一段代码。但是有一个问题,多个线程同时调用同一个方法的时候,所有线程都被排队处理了。该被调用的方法越耗时,线程越多的时候,等待的线程等待的时间也就越长,甚至于几分钟或者几十分钟。对于Web等对反应时间要求很高的系统来说,这是不可以接受的。本文就介绍一种自己实现的锁定方法,可以在没有拿到锁之后马上返回,告诉客户稍候重试。

  某一段程序同一时刻需要保证只能单线程调用,那么策略很简单,最先到的线程获取锁成功,在它释放之前其它线程都会获取失败。首先要构造一个全局的系统锁仓库,代码如下:

/*
 * 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);
 }
}

  通过以上设计,系统内部任何耗时且需要保证单线程的地方都可以用该方法实现非阻塞式的访问,提高用户体验。甚至于有的调用本身就要求这样的设计,只需处理一次,比如做日终。锁名的自定义带来了锁粒度的灵活设定,可以在运行时根据参数实现任意级别的锁定。








====================================分割线================================



最新内容请见作者的GitHub页:http://qaseven.github.io/

目录
相关文章
|
9天前
|
存储 Java 数据库连接
java多线程之线程通信
java多线程之线程通信
|
9天前
|
安全 Java 开发者
深入理解Java并发编程:线程安全与性能优化
【4月更文挑战第9天】本文将深入探讨Java并发编程的核心概念,包括线程安全和性能优化。我们将详细解析Java中的同步机制,包括synchronized关键字、Lock接口以及并发集合等,并探讨它们如何影响程序的性能。此外,我们还将讨论Java内存模型,以及它如何影响并发程序的行为。最后,我们将提供一些实用的并发编程技巧和最佳实践,帮助开发者编写出既线程安全又高效的Java程序。
22 3
|
9天前
|
算法 Java 开发者
Java中的多线程编程:概念、实现与性能优化
【4月更文挑战第9天】在Java编程中,多线程是一种强大的工具,它允许开发者创建并发执行的程序,提高系统的响应性和吞吐量。本文将深入探讨Java多线程的核心概念,包括线程的生命周期、线程同步机制以及线程池的使用。接着,我们将展示如何通过继承Thread类和实现Runnable接口来创建线程,并讨论各自的优缺点。此外,文章还将介绍高级主题,如死锁的预防、避免和检测,以及如何使用并发集合和原子变量来提高多线程程序的性能和安全性。最后,我们将提供一些实用的性能优化技巧,帮助开发者编写出更高效、更稳定的多线程应用程序。
|
7天前
|
安全 算法 Java
深入理解Java并发编程:线程安全与性能优化
【4月更文挑战第11天】 在Java中,高效的并发编程是提升应用性能和响应能力的关键。本文将探讨Java并发的核心概念,包括线程安全、锁机制、线程池以及并发集合等,同时提供实用的编程技巧和最佳实践,帮助开发者在保证线程安全的前提下,优化程序性能。我们将通过分析常见的并发问题,如竞态条件、死锁,以及如何利用现代Java并发工具来避免这些问题,从而构建更加健壮和高效的多线程应用程序。
|
7天前
|
Java Maven
【Java报错】显示错误“Error:java: 程序包org.springframework.boot不存在“
【Java报错】显示错误“Error:java: 程序包org.springframework.boot不存在“
30 3
|
2天前
|
存储 安全 Java
Java中的容器,线程安全和线程不安全
Java中的容器,线程安全和线程不安全
7 1
|
2天前
|
存储 缓存 安全
Java并发基础之互斥同步、非阻塞同步、指令重排与volatile
在Java中,多线程编程常常涉及到共享数据的访问,这时候就需要考虑线程安全问题。Java提供了多种机制来实现线程安全,其中包括互斥同步(Mutex Synchronization)、非阻塞同步(Non-blocking Synchronization)、以及volatile关键字等。 互斥同步(Mutex Synchronization) 互斥同步是一种基本的同步手段,它要求在任何时刻,只有一个线程可以执行某个方法或某个代码块,其他线程必须等待。Java中的synchronized关键字就是实现互斥同步的常用手段。当一个线程进入一个synchronized方法或代码块时,它需要先获得锁,如果
20 0
|
3天前
|
设计模式 运维 安全
深入理解Java并发编程:线程安全与性能优化
【4月更文挑战第15天】在Java开发中,多线程编程是提升应用程序性能和响应能力的关键手段。然而,它伴随着诸多挑战,尤其是在保证线程安全的同时如何避免性能瓶颈。本文将探讨Java并发编程的核心概念,包括同步机制、锁优化、线程池使用以及并发集合等,旨在为开发者提供实用的线程安全策略和性能优化技巧。通过实例分析和最佳实践的分享,我们的目标是帮助读者构建既高效又可靠的多线程应用。
|
4天前
|
Java 程序员 编译器
Java中的线程同步与锁优化策略
【4月更文挑战第14天】在多线程编程中,线程同步是确保数据一致性和程序正确性的关键。Java提供了多种机制来实现线程同步,其中最常用的是synchronized关键字和Lock接口。本文将深入探讨Java中的线程同步问题,并分析如何通过锁优化策略提高程序性能。我们将首先介绍线程同步的基本概念,然后详细讨论synchronized和Lock的使用及优缺点,最后探讨一些锁优化技巧,如锁粗化、锁消除和读写锁等。
|
6天前
|
Java
探秘jstack:解决Java应用线程问题的利器
探秘jstack:解决Java应用线程问题的利器
14 1
探秘jstack:解决Java应用线程问题的利器