package six.com.crawler.common;java
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;node
import redis.clients.jedis.JedisCluster;redis
/**
* @author 做者
* @E-mail: 359852326@qq.com
* @date 建立時間:2017年5月27日 下午3:13:14
*
* 基於redis實現分佈式鎖,無需給鎖key加上過時時間,程序會自動檢測
*/
public class RedisLock {app
private static long SYSTEM_START_TIME = System.currentTimeMillis();
private static String mac;
private static String pid;
private static String nodeKeepliveInfoPre;分佈式
static {
String name = ManagementFactory.getRuntimeMXBean().getName();
pid = name.split("@")[0];
try {
InetAddress ia = InetAddress.getLocalHost();
byte[] macBytes = NetworkInterface.getByInetAddress(ia).getHardwareAddress();
StringBuffer sb = new StringBuffer("");
for (int i = 0; i < macBytes.length; i++) {
int temp = macBytes[i] & 0xff;
String str = Integer.toHexString(temp);
if (str.length() == 1) {
sb.append("0" + str);
} else {
sb.append(str);
}
}
mac = sb.toString().toUpperCase();
} catch (Exception e) {
}
nodeKeepliveInfoPre = mac + "_" + pid + "_" + SYSTEM_START_TIME + "_";
}oop
private Thread keepliveThread;
private JedisCluster jedisCluster;
private String nodeKeepliveInfoKeyPre;
private String nodeKeepliveInfoKey;
private long loopKeepliveInterval;
private int keepliveInfoExpire;
private long checkLockIntervalTime;this
public RedisLock(JedisCluster jedisCluster, String nodeKeepLiveInfoKeyPre, long loopKeepliveInterval,
long checkLockIntervalTime) {
this.jedisCluster = jedisCluster;
this.nodeKeepliveInfoKeyPre = nodeKeepLiveInfoKeyPre;
this.nodeKeepliveInfoKey = getNodeKeepliveInfoKey(mac, pid, String.valueOf(SYSTEM_START_TIME));
this.loopKeepliveInterval = loopKeepliveInterval;
this.keepliveInfoExpire = (int) (loopKeepliveInterval) / 1000 * 2;
this.checkLockIntervalTime = checkLockIntervalTime;
initKeepLive();
}.net
/**
* 節點mac+進程id+進程啓動時間保證節點重啓問題
*/
private void initKeepLive() {
keepliveThread = new Thread(() -> {
String nodeInfo = null;
while (true) {
nodeInfo = nodeKeepliveInfoPre + String.valueOf(System.currentTimeMillis());
jedisCluster.set(nodeKeepliveInfoKey, nodeInfo);
jedisCluster.expire(nodeKeepliveInfoKey, keepliveInfoExpire);
try {
Thread.sleep(loopKeepliveInterval);
} catch (InterruptedException e) {
}
}進程
}, "node-keeplive-thread");
keepliveThread.setDaemon(true);
keepliveThread.start();
}get
public void lock(String lockKey) {
while (true) {
if (1 == jedisCluster.setnx(lockKey, getNodeLockInfo())) {
break;
}
String nodeInfo = jedisCluster.get(lockKey);
String nodeInfoKey = getNodeKeepliveInfoKey(nodeInfo);
String lastKeepNodeInfo = jedisCluster.get(nodeInfoKey);
do {
try {
Thread.sleep(checkLockIntervalTime);// 這個時間須要根據節點刷新時間取一個合適值
} catch (InterruptedException e) {
}
String tempNodeInfo = jedisCluster.get(nodeInfoKey);
if (isNotKeeplive(lastKeepNodeInfo, tempNodeInfo)) {
// 證實節點掛了
unlock(lockKey);
break;
} else {
lastKeepNodeInfo = tempNodeInfo;
}
} while (true);
}
}
/**
* 判斷目標節點是否還在線
*
* @param lastKeepliveInfo
* @param newKeepliveInfo
* @return
*/
private boolean isNotKeeplive(String lastKeepliveInfo, String newKeepliveInfo) {
String[] lastMeta = lastKeepliveInfo.split("_");
String[] newMeta = newKeepliveInfo.split("_");
// mac pid 啓動時間 系統時間
if (lastMeta[0] != newMeta[0]) {
// 當前Hold key的節點已被其餘節點佔據
return true;
} else {
if (lastMeta[1] != newMeta[1]) {
// pid發生變化表示節點已經重啓
return true;
} else {
if (lastMeta[2] != newMeta[2]) {
// 啓動時間發生變化表示節點已經重啓
return true;
} else {
if (lastMeta[3] != newMeta[3]) {
// 系統時間發生變化表示節點正常存活
return false;
} else {
return true;
}
}
}
}
}
public void unlock(String lockKey) {
jedisCluster.del(lockKey);
}
private String getNodeLockInfo() {
return mac + "_" + pid + "_" + SYSTEM_START_TIME + "_" + System.currentTimeMillis();
}
private String getNodeKeepliveInfoKey(String mac, String pid, String systemStartTime) {
String nodeKeepLiveInfoKey = nodeKeepliveInfoKeyPre + mac + pid + systemStartTime;
return nodeKeepLiveInfoKey;
}
private String getNodeKeepliveInfoKey(String nodeLockInfo) {
String[] meta = nodeLockInfo.split("_");
return getNodeKeepliveInfoKey(meta[0], meta[1], meta[2]);
}
}