1.采用數據庫悲觀鎖來實現同步
采用悲觀鎖來實現同步 在sql語句后加 for update就加上了鎖,在查詢的時候進行加鎖,在加鎖后不能進行查詢。提交時候后其他人才能查詢。 public static int generate(String tableName){ //使用數據庫的悲觀鎖for update String sql = "select value from t_table_id where table_name=? for update"; Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; int value = 0; try{ conn = DbUtil.getConnection(); //設置自動提交為false DbUtil.beginTransaction(conn); pstmt = conn.prepareStatement(sql); pstmt.setString(1, tableName); rs = pstmt.executeQuery(); rs.next(); // if(!rs.next()){ // throw new RuntimeException(); // } value = rs.getInt("value"); value++; modifyValueField(conn,tableName,value); //提交事務 DbUtil.commitTransaction(conn); }catch(Exception e){ e.printStackTrace(); //回滾事務 DbUtil.rollbackTranscation(conn); throw new RuntimeException(); }finally{ DbUtil.close(rs); DbUtil.close(pstmt); DbUtil.resetConnection(conn); DbUtil.close(conn); } return value; }
/**
* @author http://blog.csdn.net/java2000_wl
* @version <b>1.0.0</b>
*/
public class RedisBillLockHandler implements IBatchBillLockHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(RedisBillLockHandler.class);
private static final int DEFAULT_SINGLE_EXPIRE_TIME = 3;
private static final int DEFAULT_BATCH_EXPIRE_TIME = 6;
private final JedisPool jedisPool;
/**
* 構造
* @author http://blog.csdn.net/java2000_wl
*/
public RedisBillLockHandler(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
/**
* 獲取鎖 如果鎖可用 立即返回true, 否則返回false
* @author http://blog.csdn.net/java2000_wl
* @see com.fx.platform.components.lock.IBillLockHandler#tryLock(com.fx.platform.components.lock.IBillIdentify)
* @param billIdentify
* @return
*/
public boolean tryLock(IBillIdentify billIdentify) {
return tryLock(billIdentify, 0L, null);
}
/**
* 鎖在給定的等待時間內空閑,則獲取鎖成功 返回true, 否則返回false
* @author http://blog.csdn.net/java2000_wl
* @see com.fx.platform.components.lock.IBillLockHandler#tryLock(com.fx.platform.components.lock.IBillIdentify,
* long, java.util.concurrent.TimeUnit)
* @param billIdentify
* @param timeout
* @param unit
* @return
*/
public boolean tryLock(IBillIdentify billIdentify, long timeout, TimeUnit unit) {
String key = (String) billIdentify.uniqueIdentify();
Jedis jedis = null;
try {
jedis = getResource();
long nano = System.nanoTime();
do {
LOGGER.debug("try lock key: " + key);
Long i = jedis.setnx(key, key);
if (i == 1) {
jedis.expire(key, DEFAULT_SINGLE_EXPIRE_TIME);
LOGGER.debug("get lock, key: " + key + " , expire in " + DEFAULT_SINGLE_EXPIRE_TIME + " seconds.");
return Boolean.TRUE;
} else { // 存在鎖
if (LOGGER.isDebugEnabled()) {
String desc = jedis.get(key);
LOGGER.debug("key: " + key + " locked by another business:" + desc);
}
}
if (timeout == 0) {
break;
}
Thread.sleep(300);
} while ((System.nanoTime() - nano) < unit.toNanos(timeout));
return Boolean.FALSE;
} catch (JedisConnectionException je) {
LOGGER.error(je.getMessage(), je);
returnBrokenResource(jedis);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
} finally {
returnResource(jedis);
}
return Boolean.FALSE;
}
/**
* 如果鎖空閑立即返回 獲取失敗 一直等待
* @author http://blog.csdn.net/java2000_wl
* @see com.fx.platform.components.lock.IBillLockHandler#lock(com.fx.platform.components.lock.IBillIdentify)
* @param billIdentify
*/
public void lock(IBillIdentify billIdentify) {
String key = (String) billIdentify.uniqueIdentify();
Jedis jedis = null;
try {
jedis = getResource();
do {
LOGGER.debug("lock key: " + key);
Long i = jedis.setnx(key, key);
if (i == 1) {
jedis.expire(key, DEFAULT_SINGLE_EXPIRE_TIME);
LOGGER.debug("get lock, key: " + key + " , expire in " + DEFAULT_SINGLE_EXPIRE_TIME + " seconds.");
return;
} else {
if (LOGGER.isDebugEnabled()) {
String desc = jedis.get(key);
LOGGER.debug("key: " + key + " locked by another business:" + desc);
}
}
Thread.sleep(300);
} while (true);
} catch (JedisConnectionException je) {
LOGGER.error(je.getMessage(), je);
returnBrokenResource(jedis);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
} finally {
returnResource(jedis);
}
}
/**
* 釋放鎖
* @author http://blog.csdn.net/java2000_wl
* @see com.fx.platform.components.lock.IBillLockHandler#unLock(com.fx.platform.components.lock.IBillIdentify)
* @param billIdentify
*/
public void unLock(IBillIdentify billIdentify) {
List<IBillIdentify> list = new ArrayList<IBillIdentify>();
list.add(billIdentify);
unLock(list);
}
/**
* 批量獲取鎖 如果全部獲取 立即返回true, 部分獲取失敗 返回false
* @author http://blog.csdn.net/java2000_wl
* @date 2013-7-22 下午10:27:44
* @see com.fx.platform.components.lock.IBatchBillLockHandler#tryLock(java.util.List)
* @param billIdentifyList
* @return
*/
public boolean tryLock(List<IBillIdentify> billIdentifyList) {
return tryLock(billIdentifyList, 0L, null);
}
/**
* 鎖在給定的等待時間內空閑,則獲取鎖成功 返回true, 否則返回false
* @author http://blog.csdn.net/java2000_wl
* @param billIdentifyList
* @param timeout
* @param unit
* @return
*/
public boolean tryLock(List<IBillIdentify> billIdentifyList, long timeout, TimeUnit unit) {
Jedis jedis = null;
try {
List<String> needLocking = new CopyOnWriteArrayList<String>();
List<String> locked = new CopyOnWriteArrayList<String>();
jedis = getResource();
long nano = System.nanoTime();
do {
// 構建pipeline,批量提交
Pipeline pipeline = jedis.pipelined();
for (IBillIdentify identify : billIdentifyList) {
String key = (String) identify.uniqueIdentify();
needLocking.add(key);
pipeline.setnx(key, key);
}
LOGGER.debug("try lock keys: " + needLocking);
// 提交redis執行計數
List<Object> results = pipeline.syncAndReturnAll();
for (int i = 0; i < results.size(); ++i) {
Long result = (Long) results.get(i);
String key = needLocking.get(i);
if (result == 1) { // setnx成功,獲得鎖
jedis.expire(key, DEFAULT_BATCH_EXPIRE_TIME);
locked.add(key);
}
}
needLocking.removeAll(locked); // 已鎖定資源去除
if (CollectionUtils.isEmpty(needLocking)) {
return true;
} else {
// 部分資源未能鎖住
LOGGER.debug("keys: " + needLocking + " locked by another business:");
}
if (timeout == 0) {
break;
}
Thread.sleep(500);
} while ((System.nanoTime() - nano) < unit.toNanos(timeout));
// 得不到鎖,釋放鎖定的部分對象,並返回失敗
if (!CollectionUtils.isEmpty(locked)) {
jedis.del(locked.toArray(new String[0]));
}
return false;
} catch (JedisConnectionException je) {
LOGGER.error(je.getMessage(), je);
returnBrokenResource(jedis);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
} finally {
returnResource(jedis);
}
return true;
}
/**
* 批量釋放鎖
* @author http://blog.csdn.net/java2000_wl
* @see com.fx.platform.components.lock.IBatchBillLockHandler#unLock(java.util.List)
* @param billIdentifyList
*/
public void unLock(List<IBillIdentify> billIdentifyList) {
List<String> keys = new CopyOnWriteArrayList<String>();
for (IBillIdentify identify : billIdentifyList) {
String key = (String) identify.uniqueIdentify();
keys.add(key);
}
Jedis jedis = null;
try {
jedis = getResource();
jedis.del(keys.toArray(new String[0]));
LOGGER.debug("release lock, keys :" + keys);
} catch (JedisConnectionException je) {
LOGGER.error(je.getMessage(), je);
returnBrokenResource(jedis);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
} finally {
returnResource(jedis);
}
}
/**
* @author http://blog.csdn.net/java2000_wl
* @date 2013-7-22 下午9:33:45
* @return
*/
private Jedis getResource() {
return jedisPool.getResource();
}
/**
* 銷毀連接
* @author http://blog.csdn.net/java2000_wl
* @param jedis
*/
private void returnBrokenResource(Jedis jedis) {
if (jedis == null) {
return;
}
try {
//容錯
jedisPool.returnBrokenResource(jedis);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
/**
* @author http://blog.csdn.net/java2000_wl
* @param jedis
*/
private void returnResource(Jedis jedis) {
if (jedis == null) {
return;
}
try {
jedisPool.returnResource(jedis);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
轉自:http://www.cnblogs.com/happyday56/p/3454086.html
3.java使用zookeeper實現的分布式鎖示例
使用zookeeper實現的分布式鎖 分布式鎖,實現了Lock接口 復制代碼 代碼如下: package com.concurrent; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooDefs; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.Stat; /** DistributedLock lock = null; try { lock = new DistributedLock("127.0.0.1:2182","test"); lock.lock(); //do something... } catch (Exception e) { e.printStackTrace(); } finally { if(lock != null) lock.unlock(); } * @author xueliang * */ public class DistributedLock implements Lock, Watcher{ private ZooKeeper zk; private String root = "/locks";//根 private String lockName;//競爭資源的標志 private String waitNode;//等待前一個鎖 private String myZnode;//當前鎖 private CountDownLatch latch;//計數器 private int sessionTimeout = 30000; private List<Exception> exception = new ArrayList<Exception>(); /** * 創建分布式鎖,使用前請確認config配置的zookeeper服務可用 * @param config 127.0.0.1:2181 * @param lockName 競爭資源標志,lockName中不能包含單詞lock */ public DistributedLock(String config, String lockName){ this.lockName = lockName; // 創建一個與服務器的連接 try { zk = new ZooKeeper(config, sessionTimeout, this); Stat stat = zk.exists(root, false); if(stat == null){ // 創建根節點 zk.create(root, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); } } catch (IOException e) { exception.add(e); } catch (KeeperException e) { exception.add(e); } catch (InterruptedException e) { exception.add(e); } } /** * zookeeper節點的監視器 */ public void process(WatchedEvent event) { if(this.latch != null) { this.latch.countDown(); } } public void lock() { if(exception.size() > 0){ throw new LockException(exception.get(0)); } try { if(this.tryLock()){ System.out.println("Thread " + Thread.currentThread().getId() + " " +myZnode + " get lock true"); return; } else{ waitForLock(waitNode, sessionTimeout);//等待鎖 } } catch (KeeperException e) { throw new LockException(e); } catch (InterruptedException e) { throw new LockException(e); } } public boolean tryLock() { try { String splitStr = "_lock_"; if(lockName.contains(splitStr)) throw new LockException("lockName can not contains \\u000B"); //創建臨時子節點 myZnode = zk.create(root + "/" + lockName + splitStr, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL); System.out.println(myZnode + " is created "); //取出所有子節點 List<String> subNodes = zk.getChildren(root, false); //取出所有lockName的鎖 List<String> lockObjNodes = new ArrayList<String>(); for (String node : subNodes) { String _node = node.split(splitStr)[0]; if(_node.equals(lockName)){ lockObjNodes.add(node); } } Collections.sort(lockObjNodes); System.out.println(myZnode + "==" + lockObjNodes.get(0)); if(myZnode.equals(root+"/"+lockObjNodes.get(0))){ //如果是最小的節點,則表示取得鎖 return true; } //如果不是最小的節點,找到比自己小1的節點 String subMyZnode = myZnode.substring(myZnode.lastIndexOf("/") + 1); waitNode = lockObjNodes.get(Collections.binarySearch(lockObjNodes, subMyZnode) - 1); } catch (KeeperException e) { throw new LockException(e); } catch (InterruptedException e) { throw new LockException(e); } return false; } public boolean tryLock(long time, TimeUnit unit) { try { if(this.tryLock()){ return true; } return waitForLock(waitNode,time); } catch (Exception e) { e.printStackTrace(); } return false; } private boolean waitForLock(String lower, long waitTime) throws InterruptedException, KeeperException { Stat stat = zk.exists(root + "/" + lower,true); //判斷比自己小一個數的節點是否存在,如果不存在則無需等待鎖,同時注冊監聽 if(stat != null){ System.out.println("Thread " + Thread.currentThread().getId() + " waiting for " + root + "/" + lower); this.latch = new CountDownLatch(1); this.latch.await(waitTime, TimeUnit.MILLISECONDS); this.latch = null; } return true; } public void unlock() { try { System.out.println("unlock " + myZnode); zk.delete(myZnode,-1); myZnode = null; zk.close(); } catch (InterruptedException e) { e.printStackTrace(); } catch (KeeperException e) { e.printStackTrace(); } } public void lockInterruptibly() throws InterruptedException { this.lock(); } public Condition newCondition() { return null; } public class LockException extends RuntimeException { private static final long serialVersionUID = 1L; public LockException(String e){ super(e); } public LockException(Exception e){ super(e); } } } 並發測試工具 復制代碼 代碼如下: package com.concurrent; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; /** ConcurrentTask[] task = new ConcurrentTask[5]; for(int i=0;i<task.length;i++){ task[i] = new ConcurrentTask(){ public void run() { System.out.println("=============="); }}; } new ConcurrentTest(task); * @author xueliang * */ public class ConcurrentTest { private CountDownLatch startSignal = new CountDownLatch(1);//開始閥門 private CountDownLatch doneSignal = null;//結束閥門 private CopyOnWriteArrayList<Long> list = new CopyOnWriteArrayList<Long>(); private AtomicInteger err = new AtomicInteger();//原子遞增 private ConcurrentTask[] task = null; public ConcurrentTest(ConcurrentTask... task){ this.task = task; if(task == null){ System.out.println("task can not null"); System.exit(1); } doneSignal = new CountDownLatch(task.length); start(); } /** * @param args * @throws ClassNotFoundException */ private void start(){ //創建線程,並將所有線程等待在閥門處 createThread(); //打開閥門 startSignal.countDown();//遞減鎖存器的計數,如果計數到達零,則釋放所有等待的線程 try { doneSignal.await();//等待所有線程都執行完畢 } catch (InterruptedException e) { e.printStackTrace(); } //計算執行時間 getExeTime(); } /** * 初始化所有線程,並在閥門處等待 */ private void createThread() { long len = doneSignal.getCount(); for (int i = 0; i < len; i++) { final int j = i; new Thread(new Runnable(){ public void run() { try { startSignal.await();//使當前線程在鎖存器倒計數至零之前一直等待 long start = System.currentTimeMillis(); task[j].run(); long end = (System.currentTimeMillis() - start); list.add(end); } catch (Exception e) { err.getAndIncrement();//相當於err++ } doneSignal.countDown(); } }).start(); } } /** * 計算平均響應時間 */ private void getExeTime() { int size = list.size(); List<Long> _list = new ArrayList<Long>(size); _list.addAll(list); Collections.sort(_list); long min = _list.get(0); long max = _list.get(size-1); long sum = 0L; for (Long t : _list) { sum += t; } long avg = sum/size; System.out.println("min: " + min); System.out.println("max: " + max); System.out.println("avg: " + avg); System.out.println("err: " + err.get()); } public interface ConcurrentTask { void run(); } } 測試 復制代碼 代碼如下: package com.concurrent; import com.concurrent.ConcurrentTest.ConcurrentTask; public class ZkTest { public static void main(String[] args) { Runnable task1 = new Runnable(){ public void run() { DistributedLock lock = null; try { lock = new DistributedLock("127.0.0.1:2182","test1"); //lock = new DistributedLock("127.0.0.1:2182","test2"); lock.lock(); Thread.sleep(3000); System.out.println("===Thread " + Thread.currentThread().getId() + " running"); } catch (Exception e) { e.printStackTrace(); } finally { if(lock != null) lock.unlock(); } } }; new Thread(task1).start(); try { Thread.sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); } ConcurrentTask[] tasks = new ConcurrentTask[60]; for(int i=0;i<tasks.length;i++){ ConcurrentTask task3 = new ConcurrentTask(){ public void run() { DistributedLock lock = null; try { lock = new DistributedLock("127.0.0.1:2183","test2"); lock.lock(); System.out.println("Thread " + Thread.currentThread().getId() + " running"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }; tasks[i] = task3; } new ConcurrentTest(tasks); } }