├── README.md └── java-lock ├── .classpath ├── .project ├── .settings ├── org.eclipse.jdt.core.prefs └── org.eclipse.m2e.core.prefs ├── pom.xml ├── src └── main │ └── java │ └── com │ └── lock │ ├── OrderNumGenerator.java │ └── service │ ├── Lock.java │ ├── OrderService.java │ ├── ZookeeperAbstractLock.java │ └── ZookeeperDistrbuteLock.java └── target └── classes ├── META-INF ├── MANIFEST.MF └── maven │ └── com.itmayiedu │ └── java-lock │ ├── pom.properties │ └── pom.xml └── com └── itmayiedu ├── OrderNumGenerator.class └── service ├── Lock.class ├── OrderService.class ├── ZookeeperAbstractLock.class ├── ZookeeperDistrbuteLock$1.class └── ZookeeperDistrbuteLock.class /README.md: -------------------------------------------------------------------------------- 1 | # java-lock 2 | java版本的用Zookeeper实现的分布式锁 3 | 4 | 代码已经测过,可以直接使用! 5 | 6 | #业务场景 7 | 8 | 在分布式情况,生成全局订单号ID 9 | 10 | 生成订单号方案 11 | 12 | 1. 使用时间戳 13 | 14 | 2. 使用UUID 15 | 16 | 3. 推特 (Twitter) 的 Snowflake 算法——用于生成唯一 ID 17 | 18 | #产生问题 19 | 20 | 在分布式(集群)环境下,每台JVM不能实现同步,在分布式场景下使用时间戳生成订单号可能会重复 21 | 22 | #分布式情况下,怎么解决订单号生成不重复 23 | 24 | 1. 使用分布式锁 25 | 26 | 2. 提前生成好,订单号,存放在redis取。获取订单号,直接从redis中取。 27 | 28 | #使用分布式锁生成订单号技术 29 | 30 | 1.使用数据库实现分布式锁 31 | 32 | 缺点:性能差、线程出现异常时,容易出现死锁 33 | 34 | 2.使用redis实现分布式锁 35 | 36 | 缺点:锁的失效时间难控制、容易产生死锁、非阻塞式、不可重入 37 | 38 | 3.使用zookeeper实现分布式锁 39 | 40 | 实现相对简单、可靠性强、使用临时节点,失效时间容易控制 41 | 42 | 什么是分布式锁 43 | 44 | 分布式锁一般用在分布式系统或者多个应用中,用来控制同一任务是否执行或者任务的执行顺序。在项目中,部署了多个tomcat应用,在执行定时任务时就会遇到同一任 45 | 46 | 务可能执行多次的情况,我们可以借助分布式锁,保证在同一时间只有一个tomcat应用执行了定时任务 47 | 48 | #使用Zookeeper实现分布式锁 49 | 50 | #Zookeeper实现分布式锁原理 51 | 52 | 使用zookeeper创建临时序列节点来实现分布式锁,适用于顺序执行的程序,大体思路就是创建临时序列节点,找出最小的序列节点,获取分布式锁,程序执行完成之后此序列节点消失,通过watch来监控节点的变化,从剩下的节点的找到最小的序列节点,获取分布式锁,执行相应处理,依次类推…… 53 | 54 | -------------------------------------------------------------------------------- /java-lock/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /java-lock/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | java-lock 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | -------------------------------------------------------------------------------- /java-lock/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 3 | org.eclipse.jdt.core.compiler.compliance=1.5 4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 5 | org.eclipse.jdt.core.compiler.source=1.5 6 | -------------------------------------------------------------------------------- /java-lock/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /java-lock/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | com.itmayiedu 4 | java-lock 5 | 0.0.1-SNAPSHOT 6 | 7 | 8 | com.101tec 9 | zkclient 10 | 0.10 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /java-lock/src/main/java/com/lock/OrderNumGenerator.java: -------------------------------------------------------------------------------- 1 | package com.lock; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | //生成订单号规则 使用时间戳+业务id 7 | public class OrderNumGenerator { 8 | // 业务ID 9 | private static int count = 0; 10 | 11 | // 生成订单号 12 | public String getNumber() { 13 | try { 14 | Thread.sleep(200); 15 | } catch (Exception e) { 16 | // TODO: handle exception 17 | } 18 | SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); 19 | return simpt.format(new Date()) + "-" + ++count; 20 | 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /java-lock/src/main/java/com/lock/service/Lock.java: -------------------------------------------------------------------------------- 1 | package com.lock.service; 2 | 3 | 4 | // lock 锁 定义分布式锁 5 | public interface Lock { 6 | 7 | //获取锁 8 | public void getLock(); 9 | //释放锁 10 | public void unLock(); 11 | } 12 | -------------------------------------------------------------------------------- /java-lock/src/main/java/com/lock/service/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.lock.service; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | import com.itmayiedu.OrderNumGenerator; 7 | 8 | // 订单生成调用业务逻辑 9 | public class OrderService implements Runnable { 10 | // 生成订单号 11 | OrderNumGenerator orderNumGenerator = new OrderNumGenerator(); 12 | // 重入锁 13 | // private Lock lock = new ReentrantLock(); 14 | private com.itmayiedu.service.Lock lock = new ZookeeperDistrbuteLock(); 15 | 16 | public void run() { 17 | try { 18 | // 上锁 19 | lock.getLock(); 20 | // synchronized (this) { 21 | // 模拟用户生成订单号 22 | getNumber(); 23 | } catch (Exception e) { 24 | e.printStackTrace(); 25 | } finally { 26 | // 釋放鎖資源 27 | lock.unLock(); 28 | } 29 | } 30 | 31 | public void getNumber() { 32 | String number = orderNumGenerator.getNumber(); 33 | System.out.println(Thread.currentThread().getName() + ",##number:" + number); 34 | } 35 | 36 | public static void main(String[] args) { 37 | System.out.println("##模拟生成订单号开始..."); 38 | 39 | for (int i = 0; i < 100; i++) { 40 | new Thread(new OrderService()).start(); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /java-lock/src/main/java/com/lock/service/ZookeeperAbstractLock.java: -------------------------------------------------------------------------------- 1 | package com.lock.service; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | 5 | import org.I0Itec.zkclient.ZkClient; 6 | 7 | //重构重复代码,将重复代码交给子类执行 8 | public abstract class ZookeeperAbstractLock implements Lock { 9 | // zk连接地址 10 | private static final String CONNECTSTRING = "127.0.0.1:2181"; 11 | // 创建zk连接 12 | protected ZkClient zkClient = new ZkClient(CONNECTSTRING); 13 | protected static final String PATH = "/lock"; 14 | protected CountDownLatch countDownLatch = null; 15 | 16 | public void getLock() { 17 | if (tryLock()) { 18 | System.out.println("###获取锁成功#####"); 19 | } else { 20 | // 等待 21 | waitLock(); 22 | // 重新获取锁 23 | getLock(); 24 | } 25 | } 26 | 27 | // 是否获取锁成功,成功返回true 失败返回fasle 28 | abstract Boolean tryLock(); 29 | 30 | // 等待 31 | abstract void waitLock(); 32 | 33 | public void unLock() { 34 | if (zkClient != null) { 35 | zkClient.close(); 36 | System.out.println("释放锁资源"); 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /java-lock/src/main/java/com/lock/service/ZookeeperDistrbuteLock.java: -------------------------------------------------------------------------------- 1 | package com.lock.service; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | 5 | import org.I0Itec.zkclient.IZkDataListener; 6 | 7 | public class ZookeeperDistrbuteLock extends ZookeeperAbstractLock { 8 | 9 | @Override 10 | Boolean tryLock() { 11 | try { 12 | zkClient.createEphemeral(PATH); 13 | return true; 14 | } catch (Exception e) { 15 | return false; 16 | } 17 | 18 | } 19 | 20 | @Override 21 | void waitLock() { 22 | 23 | // 使用事件监听,获取到节点被删除, 24 | IZkDataListener iZkDataListener = new IZkDataListener() { 25 | // 当节点被删除 26 | public void handleDataDeleted(String dataPath) throws Exception { 27 | if (countDownLatch != null) { 28 | // 唤醒 29 | countDownLatch.countDown(); 30 | } 31 | 32 | } 33 | 34 | // 当节点发生改变 35 | public void handleDataChange(String dataPath, Object data) throws Exception { 36 | 37 | } 38 | }; 39 | 40 | // 注册节点信息 41 | zkClient.subscribeDataChanges(PATH, iZkDataListener); 42 | if (zkClient.exists(PATH)) { 43 | // 创建信号量 44 | countDownLatch = new CountDownLatch(1); 45 | try { 46 | // 等待 47 | countDownLatch.await(); 48 | } catch (Exception e) { 49 | 50 | } 51 | 52 | } 53 | // 删除事件通知 54 | zkClient.unsubscribeDataChanges(PATH, iZkDataListener); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /java-lock/target/classes/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Built-By: Administrator 3 | Build-Jdk: 1.8.0_101 4 | Created-By: Maven Integration for Eclipse 5 | 6 | -------------------------------------------------------------------------------- /java-lock/target/classes/META-INF/maven/com.itmayiedu/java-lock/pom.properties: -------------------------------------------------------------------------------- 1 | #Generated by Maven Integration for Eclipse 2 | #Sat Mar 03 22:27:12 CST 2018 3 | version=0.0.1-SNAPSHOT 4 | groupId=com.itmayiedu 5 | m2e.projectName=java-lock 6 | m2e.projectLocation=F\:\\itmayiedujiangke2018-02-24\\java-lock 7 | artifactId=java-lock 8 | -------------------------------------------------------------------------------- /java-lock/target/classes/META-INF/maven/com.itmayiedu/java-lock/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | com.itmayiedu 4 | java-lock 5 | 0.0.1-SNAPSHOT 6 | 7 | 8 | com.101tec 9 | zkclient 10 | 0.10 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /java-lock/target/classes/com/itmayiedu/OrderNumGenerator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anlijie/java-lock/c46a1151a90e94c9e8f2e835a125b8ff0a8cb421/java-lock/target/classes/com/itmayiedu/OrderNumGenerator.class -------------------------------------------------------------------------------- /java-lock/target/classes/com/itmayiedu/service/Lock.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anlijie/java-lock/c46a1151a90e94c9e8f2e835a125b8ff0a8cb421/java-lock/target/classes/com/itmayiedu/service/Lock.class -------------------------------------------------------------------------------- /java-lock/target/classes/com/itmayiedu/service/OrderService.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anlijie/java-lock/c46a1151a90e94c9e8f2e835a125b8ff0a8cb421/java-lock/target/classes/com/itmayiedu/service/OrderService.class -------------------------------------------------------------------------------- /java-lock/target/classes/com/itmayiedu/service/ZookeeperAbstractLock.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anlijie/java-lock/c46a1151a90e94c9e8f2e835a125b8ff0a8cb421/java-lock/target/classes/com/itmayiedu/service/ZookeeperAbstractLock.class -------------------------------------------------------------------------------- /java-lock/target/classes/com/itmayiedu/service/ZookeeperDistrbuteLock$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anlijie/java-lock/c46a1151a90e94c9e8f2e835a125b8ff0a8cb421/java-lock/target/classes/com/itmayiedu/service/ZookeeperDistrbuteLock$1.class -------------------------------------------------------------------------------- /java-lock/target/classes/com/itmayiedu/service/ZookeeperDistrbuteLock.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anlijie/java-lock/c46a1151a90e94c9e8f2e835a125b8ff0a8cb421/java-lock/target/classes/com/itmayiedu/service/ZookeeperDistrbuteLock.class --------------------------------------------------------------------------------