码迷,mamicode.com
首页 > 其他好文 > 详细

分布式并发锁处理

时间:2016-05-09 14:01:57      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:

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;
        }

2.Redis实现分布式锁

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

 

分布式并发锁处理

标签:

原文地址:http://www.cnblogs.com/harry335/p/5473480.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!