├── .gitignore
├── README.md
├── src
└── main
│ ├── webapp
│ ├── index.jsp
│ └── WEB-INF
│ │ └── web.xml
│ └── java
│ ├── redis
│ ├── ThreadA.java
│ ├── Test.java
│ ├── Service.java
│ └── DistributedLock.java
│ └── zookeeper
│ ├── Test.java
│ └── DistributedLock.java
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | /target/*
2 | /.idea/*
3 | /*.iml
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # **分布式锁的简单实现**
2 |
3 | ## **基于Redis实现分布式锁**
4 |
5 | ## **基于ZooKeeper实现分布式锁**
--------------------------------------------------------------------------------
/src/main/webapp/index.jsp:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World!
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/webapp/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | Archetype Created Web Application
7 |
8 |
--------------------------------------------------------------------------------
/src/main/java/redis/ThreadA.java:
--------------------------------------------------------------------------------
1 | package redis;
2 |
3 | /**
4 | * Created by liuyang on 2017/4/20.
5 | */
6 | public class ThreadA extends Thread {
7 | private Service service;
8 |
9 | public ThreadA(Service service) {
10 | this.service = service;
11 | }
12 |
13 | @Override
14 | public void run() {
15 | service.seckill();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/redis/Test.java:
--------------------------------------------------------------------------------
1 | package redis;
2 |
3 | /**
4 | * Created by liuyang on 2017/4/20.
5 | */
6 | public class Test {
7 | public static void main(String[] args) {
8 | Service service = new Service();
9 | for (int i = 0; i < 50; i++) {
10 | ThreadA threadA = new ThreadA(service);
11 | threadA.start();
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/zookeeper/Test.java:
--------------------------------------------------------------------------------
1 | package zookeeper;
2 |
3 | /**
4 | * Created by liuyang on 2017/4/20.
5 | */
6 | public class Test {
7 | static int n = 500;
8 |
9 | public static void secskill() {
10 | System.out.println(--n);
11 | }
12 |
13 | public static void main(String[] args) {
14 |
15 |
16 | Runnable runnable = new Runnable() {
17 | public void run() {
18 | DistributedLock lock = null;
19 | try {
20 | lock = new DistributedLock("127.0.0.1:2181", "test1");
21 | lock.lock();
22 | secskill();
23 | System.out.println(Thread.currentThread().getName() + "正在运行");
24 | } finally {
25 | if (lock != null) {
26 | lock.unlock();
27 | }
28 | }
29 | }
30 | };
31 |
32 | for (int i = 0; i < 10; i++) {
33 | Thread t = new Thread(runnable);
34 | t.start();
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/redis/Service.java:
--------------------------------------------------------------------------------
1 | package redis;
2 |
3 | import redis.clients.jedis.JedisPool;
4 | import redis.clients.jedis.JedisPoolConfig;
5 |
6 | /**
7 | * Created by liuyang on 2017/4/20.
8 | */
9 | public class Service {
10 | private static JedisPool pool = null;
11 |
12 | static {
13 | JedisPoolConfig config = new JedisPoolConfig();
14 | // 设置最大连接数
15 | config.setMaxTotal(200);
16 | // 设置最大空闲数
17 | config.setMaxIdle(8);
18 | // 设置最大等待时间
19 | config.setMaxWaitMillis(1000 * 100);
20 | // 在borrow一个jedis实例时,是否需要验证,若为true,则所有jedis实例均是可用的
21 | config.setTestOnBorrow(true);
22 | pool = new JedisPool(config, "127.0.0.1", 6379, 3000);
23 | }
24 |
25 | DistributedLock lock = new DistributedLock(pool);
26 |
27 | int n = 500;
28 |
29 | public void seckill() {
30 | // 返回锁的value值,供释放锁时候进行判断
31 | String indentifier = lock.lockWithTimeout("resource", 5000, 1000);
32 | System.out.println(Thread.currentThread().getName() + "获得了锁");
33 | System.out.println(--n);
34 | lock.releaseLock("resource", indentifier);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | cn.liu5599
5 | distributedlock
6 | war
7 | 1.0-SNAPSHOT
8 | distributedlock Maven Webapp
9 | http://maven.apache.org
10 |
11 |
12 | junit
13 | junit
14 | 3.8.1
15 | test
16 |
17 |
18 |
19 |
20 | redis.clients
21 | jedis
22 | 2.9.0
23 |
24 |
25 |
26 |
27 | org.apache.zookeeper
28 | zookeeper
29 | 3.4.9
30 |
31 |
32 |
33 |
34 |
35 | distributedlock
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/main/java/redis/DistributedLock.java:
--------------------------------------------------------------------------------
1 | package redis;
2 |
3 | import redis.clients.jedis.Jedis;
4 | import redis.clients.jedis.JedisPool;
5 | import redis.clients.jedis.Transaction;
6 | import redis.clients.jedis.exceptions.JedisException;
7 |
8 | import java.util.List;
9 | import java.util.UUID;
10 |
11 | /**
12 | * Created by liuyang on 2017/4/20.
13 | */
14 | public class DistributedLock {
15 | private final JedisPool jedisPool;
16 |
17 | public DistributedLock(JedisPool jedisPool) {
18 | this.jedisPool = jedisPool;
19 | }
20 |
21 | /**
22 | * 加锁
23 | * @param locaName 锁的key
24 | * @param acquireTimeout 获取超时时间
25 | * @param timeout 锁的超时时间
26 | * @return 锁标识
27 | */
28 | public String lockWithTimeout(String locaName,
29 | long acquireTimeout, long timeout) {
30 | Jedis conn = null;
31 | String retIdentifier = null;
32 | try {
33 | // 获取连接
34 | conn = jedisPool.getResource();
35 | // 随机生成一个value
36 | String identifier = UUID.randomUUID().toString();
37 | // 锁名,即key值
38 | String lockKey = "lock:" + locaName;
39 | // 超时时间,上锁后超过此时间则自动释放锁
40 | int lockExpire = (int)(timeout / 1000);
41 |
42 | // 获取锁的超时时间,超过这个时间则放弃获取锁
43 | long end = System.currentTimeMillis() + acquireTimeout;
44 | while (System.currentTimeMillis() < end) {
45 | if (conn.setnx(lockKey, identifier) == 1) {
46 | conn.expire(lockKey, lockExpire);
47 | // 返回value值,用于释放锁时间确认
48 | retIdentifier = identifier;
49 | return retIdentifier;
50 | }
51 | // 返回-1代表key没有设置超时时间,为key设置一个超时时间
52 | if (conn.ttl(lockKey) == -1) {
53 | conn.expire(lockKey, lockExpire);
54 | }
55 |
56 | try {
57 | Thread.sleep(10);
58 | } catch (InterruptedException e) {
59 | Thread.currentThread().interrupt();
60 | }
61 | }
62 | } catch (JedisException e) {
63 | e.printStackTrace();
64 | } finally {
65 | if (conn != null) {
66 | conn.close();
67 | }
68 | }
69 | return retIdentifier;
70 | }
71 |
72 | /**
73 | * 释放锁
74 | * @param lockName 锁的key
75 | * @param identifier 释放锁的标识
76 | * @return
77 | */
78 | public boolean releaseLock(String lockName, String identifier) {
79 | Jedis conn = null;
80 | String lockKey = "lock:" + lockName;
81 | boolean retFlag = false;
82 | try {
83 | conn = jedisPool.getResource();
84 | while (true) {
85 | // 监视lock,准备开始事务
86 | conn.watch(lockKey);
87 | // 通过前面返回的value值判断是不是该锁,若是该锁,则删除,释放锁
88 | if (identifier.equals(conn.get(lockKey))) {
89 | Transaction transaction = conn.multi();
90 | transaction.del(lockKey);
91 | List