什么是分布式锁?为什么要使用分布式锁?
分布式锁,是控制分布式系统之间同步访问共享资源的一种方式。
在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。-
分布式锁一般有三种实现方式:
- 数据库乐观锁:对字段增加唯一性约束
- 基于Redis的分布式锁:使用setnx、getset、expire、del这4个redis命令实现
- 基于Zookeeper的分布式锁
基于Redis的分布式锁的实现
package com.dg.dt.etl.util;
import org.springframework.util.StringUtils;
import redis.clients.jedis.Jedis;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* @author Jum
* 基于Redis实现分布式锁
*/
public class RedisLock {
public static final String url = "jdbc:mysql://127.0.0.1:3306/data?allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&useSSL=false&zeroDateTimeBehavior=convertToNull";
public static final String name = "com.mysql.jdbc.Driver";
public static final String user = "root";
public static final String password = "root";
static int count = 10;
public static void main(String[] args) {
while (count > 0) {
count--;
new Thread(new Runnable() {
@Override
public void run() {
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.auth("bigpass");
// 锁
String lock = lock(jedis);
if (lock != null) {
Statement statement = null;
Connection conn = null;
ResultSet resultSet = null;
try {
Class.forName(name);
conn = DriverManager.getConnection(url, user, password);
statement = conn.createStatement();
String querySql = "SELECT id,name,count FROM tb_mall_prod WHERE id=100";
resultSet = statement.executeQuery(querySql);
while (resultSet.next()) {
System.out.println(Thread.currentThread().getName() + "抢到了锁 id: "
+ resultSet.getString("id")
+ " name: " + resultSet.getString("name")
+ " count: " + resultSet.getString("count"));
count = Integer.valueOf(resultSet.getString("count"));
}
// 当库存小于0时,退出程序
if (count <= 0)
return;
String updateSql = "UPDATE tb_mall_prod SET count=" + (count - 1) + " WHERE id=100";
// 更新库存
int rows = statement.executeUpdate(updateSql);
if (rows > 0) {
System.out.println("update succeed" + Thread.currentThread().getName() + " 库存剩余:" + (count - 1));
System.out.println(Thread.currentThread().getName() + " === > >start");
// 开始解锁
boolean unlock = unlock(jedis, lock);
if (unlock)
System.out.println(Thread.currentThread().getName() + " === > >succeed");
} else {
System.out.println("fail" + Thread.currentThread().getName());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
try {
if (conn != null)
conn.close();
if (statement != null)
statement.close();
if (resultSet != null)
resultSet.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}, "thread" + count).start();
}
}
/**
* 加锁
*
* @param jedis
* @return
*/
public static String lock(Jedis jedis) {
try {
while (true) {
// 设置锁的时间
String lockTime = Long.valueOf(jedis.time().get(0)) + 5 + "";
// 设置成功返回1,失败返回0
if (jedis.setnx("lock", lockTime) == 1) {
// 设置key的过期时间
jedis.expire("lock", 5);
return lockTime;
}
String lock = jedis.get("lock");
if (!StringUtils.isEmpty(lock) && Long.valueOf(lock) < Long.valueOf(jedis.time().get(0))) {
String oldLockTime = jedis.getSet("lock", lockTime);
if (!StringUtils.isEmpty(oldLockTime) && oldLockTime.equals(lock)) {
return lockTime;
}
}
Thread.sleep(100);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 解锁
*
* @param jedis
* @param lockTag
* @return
*/
public static boolean unlock(Jedis jedis, String lockTag) {
if (lockTag.equals(jedis.get("lock"))) {
jedis.del("lock");
return true;
}
return false;
}
}
图片.png