以下将详细说明几种常见的Java分布式锁解决方案,并提供具体的实现示例。
1. 基于Redis的分布式锁
实现原理
- 使用Redis的SET命令的NX(仅当key不存在时设置)和EX(设置过期时间)选项来实现锁的获取。
- 使用DEL命令来释放锁。
示例代码
import redis.clients.jedis.Jedis;
public class RedisDistributedLock {
private Jedis jedis;
private String lockKey;
private int expireTime; // 锁的过期时间,单位:秒
public RedisDistributedLock(Jedis jedis, String lockKey, int expireTime) {
this.jedis = jedis;
this.lockKey = lockKey;
this.expireTime = expireTime;
}
public boolean tryLock() {
String result = jedis.set(lockKey, "locked", "NX", "EX", expireTime);
return "OK".equals(result);
}
public void unlock() {
jedis.del(lockKey);
}
}
// 使用示例
public class Example {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost", 6379);
RedisDistributedLock lock = new RedisDistributedLock(jedis, "my_lock", 10);
if (lock.tryLock()) {
try {
// 执行临界区代码
System.out.println("执行临界区代码");
} finally {
lock.unlock();
}
} else {
System.out.println("无法获取锁");
}
}
}
2. 基于Zookeeper的分布式锁
实现原理
- 在Zookeeper中创建一个顺序节点。
- 获取当前节点的前驱节点,如果前驱节点是父节点,则当前节点获得锁。
示例代码
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import java.util.List;
public class ZookeeperDistributedLock implements Watcher {
private ZooKeeper zookeeper;
private String lockPath;
private String nodePath;
private String myNodeName;
public ZookeeperDistributedLock(ZooKeeper zookeeper, String lockPath) {
this.zookeeper = zookeeper;
this.lockPath = lockPath;
}
public boolean tryLock() throws Exception {
myNodeName = zookeeper.create(lockPath + "/lock-", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
List<String> children = zookeeper.getChildren(lockPath, this);
if (children.isEmpty()) {
return true;
}
String firstChild = children.get(0);
if (myNodeName.endsWith(firstChild)) {
return true;
}
return false;
}
public void unlock() throws Exception {
zookeeper.delete(nodePath, -1);
}
@Override
public void process(WatchedEvent event) {
// 监听事件处理
}
}
// 使用示例
public class Example {
public static void main(String[] args) throws Exception {
ZooKeeper zookeeper = new ZooKeeper("localhost:2181", 5000, new ZookeeperDistributedLock(zookeeper, "/locks"));
ZookeeperDistributedLock lock = new ZookeeperDistributedLock(zookeeper, "/locks");
if (lock.tryLock()) {
try {
// 执行临界区代码
System.out.println("执行临界区代码");
} finally {
lock.unlock();
}
} else {
System.out.println("无法获取锁");
}
}
}
3. 使用数据库实现分布式锁
实现原理
- 在数据库中创建一个锁表,使用SELECT ... FOR UPDATE来获取锁。
- 使用UPDATE来释放锁。
示例代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class DatabaseDistributedLock {
private Connection connection;
private String tableName = "distributed_lock";
public DatabaseDistributedLock(String url, String username, String password) throws Exception {
connection = DriverManager.getConnection(url, username, password);
}
public boolean tryLock(String lockName) throws Exception {
String sql = "SELECT * FROM " + tableName + " WHERE lock_name = ? FOR UPDATE";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, lockName);
ResultSet rs = statement.executeQuery();
if (!rs.next()) {
String insertSql = "INSERT INTO " + tableName + "(lock_name) VALUES (?)";
PreparedStatement insertStatement = connection.prepareStatement(insertSql);
insertStatement.setString(1, lockName);
int rows = insertStatement.executeUpdate();
return rows > 0;
}
return false;
}
public void unlock(String lockName) throws Exception {
String sql = "DELETE FROM " + tableName + " WHERE lock_name = ?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, lockName);
statement.executeUpdate();
}
}
// 使用示例
public class Example {
public static void main(String[] args) {
try {
DatabaseDistributedLock lock = new DatabaseDistributedLock("jdbc:mysql://localhost:3306/mydb", "root", "password");
if (lock.tryLock("my_lock")) {
try {
// 执行临界区代码
System.out.println("执行临界区代码");
} finally {
lock.unlock("my_lock");
}
} else {
System.out.println("无法获取锁");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
总结
以上三种方式是常见的Java分布式锁实现方法。选择哪种方法取决于你的具体需求和技术栈:
- Redis:简单易用,适合轻量级应用。
- Zookeeper:功能强大,适合复杂分布式环境。
- 数据库:适用于事务处理,但性能较低。