diff --git a/src/main/java/com/kwan/shuyu/Ticket12306.java b/src/main/java/com/kwan/shuyu/Ticket12306.java new file mode 100644 index 0000000000000000000000000000000000000000..318472fdf4a8d39ad43a7a16201d222bb55f37af --- /dev/null +++ b/src/main/java/com/kwan/shuyu/Ticket12306.java @@ -0,0 +1,65 @@ +package com.kwan.shuyu; + +import org.apache.curator.RetryPolicy; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.recipes.locks.InterProcessMutex; +import org.apache.curator.retry.ExponentialBackoffRetry; + +import java.util.concurrent.TimeUnit; + +/** + * 12306买票 + * + * @author : qinyingjie + * @version : 2.2.0 + * @date : 2023/5/14 19:17 + */ +public class Ticket12306 implements Runnable { + + /** + * 数据库的票数 + */ + private int tickets = 10; + private InterProcessMutex lock; + + public Ticket12306() { + //重试策略 + RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10); + //2.第二种方式 + //CuratorFrameworkFactory.builder(); + CuratorFramework client = CuratorFrameworkFactory.builder() + .connectString("192.168.149.135:2181") + .sessionTimeoutMs(60 * 1000) + .connectionTimeoutMs(15 * 1000) + .retryPolicy(retryPolicy) + .build(); + //开启连接 + client.start(); + lock = new InterProcessMutex(client, "/lock"); + } + + @Override + public void run() { + while (true) { + //获取锁 + try { + lock.acquire(3, TimeUnit.SECONDS); + if (tickets > 0) { + System.out.println(Thread.currentThread() + ":" + tickets); + Thread.sleep(100); + tickets--; + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + //释放锁 + try { + lock.release(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties new file mode 100644 index 0000000000000000000000000000000000000000..f380fa2196d4572fd1aa417edde73778242707b5 --- /dev/null +++ b/src/main/resources/log4j.properties @@ -0,0 +1,6 @@ +log4j.rootLogger=off,stdout + +log4j.appender.stdout = org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target = System.out +log4j.appender.stdout.layout = org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern = [%d{yyyy-MM-dd HH/:mm/:ss}]%-5p %c(line/:%L) %x-%m%n \ No newline at end of file diff --git a/src/test/java/com/kwan/shuyu/CuratorTest.java b/src/test/java/com/kwan/shuyu/CuratorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9e43155a940f2ea58e72193c173d56e2ed8e9f49 --- /dev/null +++ b/src/test/java/com/kwan/shuyu/CuratorTest.java @@ -0,0 +1,192 @@ +package com.kwan.shuyu; + +import org.apache.curator.RetryPolicy; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.api.BackgroundCallback; +import org.apache.curator.framework.api.CuratorEvent; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.data.Stat; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +public class CuratorTest { + private CuratorFramework client; + + /** + * 建立连接 + */ + @Before + public void testConnect() { + /* + * + * @param connectString 连接字符串。zk server 地址和端口 "192.168.149.135:2181,192.168.149.136:2181" + * @param sessionTimeoutMs 会话超时时间 单位ms + * @param connectionTimeoutMs 连接超时时间 单位ms + * @param retryPolicy 重试策略 + */ + /* //重试策略 + RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,10); + //1.第一种方式 + CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.149.135:2181", + 60 * 1000, 15 * 1000, retryPolicy);*/ + //重试策略 + RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10); + //2.第二种方式 + //CuratorFrameworkFactory.builder(); + client = CuratorFrameworkFactory.builder() + .connectString("192.168.149.135:2181") + .sessionTimeoutMs(60 * 1000) + .connectionTimeoutMs(15 * 1000) + .retryPolicy(retryPolicy) + .namespace("itheima") + .build(); + //开启连接 + client.start(); + } +//==============================create============================================================================= + + /** + * 创建节点:create 持久 临时 顺序 数据 + * 1. 基本创建 :create().forPath("") + * 2. 创建节点 带有数据:create().forPath("",data) + * 3. 设置节点的类型:create().withMode().forPath("",data) + * 4. 创建多级节点 /app1/p1 :create().creatingParentsIfNeeded().forPath("",data) + */ + @Test + public void testCreate() throws Exception { + //2. 创建节点 带有数据 + //如果创建节点,没有指定数据,则默认将当前客户端的ip作为数据存储 + String path = client.create().forPath("/app2", "hehe".getBytes()); + System.out.println(path); + } + + @Test + public void testCreate2() throws Exception { + //1. 基本创建 + //如果创建节点,没有指定数据,则默认将当前客户端的ip作为数据存储 + String path = client.create().forPath("/app1"); + System.out.println(path); + } + + @Test + public void testCreate3() throws Exception { + //3. 设置节点的类型 + //默认类型:持久化 + String path = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3"); + System.out.println(path); + } + + @Test + public void testCreate4() throws Exception { + //4. 创建多级节点 /app1/p1 + //creatingParentsIfNeeded():如果父节点不存在,则创建父节点 + String path = client.create().creatingParentsIfNeeded().forPath("/app4/p1"); + System.out.println(path); + } +//===========================get================================================================================ + + /** + * 查询节点: + * 1. 查询数据:get: getData().forPath() + * 2. 查询子节点: ls: getChildren().forPath() + * 3. 查询节点状态信息:ls -s:getData().storingStatIn(状态对象).forPath() + */ + @Test + public void testGet1() throws Exception { + //1. 查询数据:get + byte[] data = client.getData().forPath("/app1"); + System.out.println(new String(data)); + } + + @Test + public void testGet2() throws Exception { + // 2. 查询子节点: ls + List path = client.getChildren().forPath("/"); + System.out.println(path); + } + + @Test + public void testGet3() throws Exception { + Stat status = new Stat(); + System.out.println(status); + //3. 查询节点状态信息:ls -s + client.getData().storingStatIn(status).forPath("/app1"); + System.out.println(status); + } + //===========================set================================================================================ + + /** + * 修改数据 + * 1. 基本修改数据:setData().forPath() + * 2. 根据版本修改: setData().withVersion().forPath() + * * version 是通过查询出来的。目的就是为了让其他客户端或者线程不干扰我。 + * + * @throws Exception + */ + @Test + public void testSet() throws Exception { + client.setData().forPath("/app1", "itcast".getBytes()); + } + + @Test + public void testSetForVersion() throws Exception { + Stat status = new Stat(); + //3. 查询节点状态信息:ls -s + client.getData().storingStatIn(status).forPath("/app1"); + int version = status.getVersion();//查询出来的 3 + System.out.println(version); + client.setData().withVersion(version).forPath("/app1", "hehe".getBytes()); + } + //===========================delete================================================================================ + + /** + * 删除节点: delete deleteall + * 1. 删除单个节点:delete().forPath("/app1"); + * 2. 删除带有子节点的节点:delete().deletingChildrenIfNeeded().forPath("/app1"); + * 3. 必须成功的删除:为了防止网络抖动。本质就是重试。 client.delete().guaranteed().forPath("/app2"); + * 4. 回调:inBackground + * + * @throws Exception + */ + @Test + public void testDelete() throws Exception { + // 1. 删除单个节点 + client.delete().forPath("/app1"); + } + + @Test + public void testDelete2() throws Exception { + //2. 删除带有子节点的节点 + client.delete().deletingChildrenIfNeeded().forPath("/app4"); + } + + @Test + public void testDelete3() throws Exception { + //3. 必须成功的删除 + client.delete().guaranteed().forPath("/app2"); + } + + @Test + public void testDelete4() throws Exception { + //4. 回调 + client.delete().guaranteed().inBackground(new BackgroundCallback() { + @Override + public void processResult(CuratorFramework client, CuratorEvent event) throws Exception { + System.out.println("我被删除了~"); + System.out.println(event); + } + }).forPath("/app1"); + } + + @After + public void close() { + if (client != null) { + client.close(); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/kwan/shuyu/CuratorWatcherTest.java b/src/test/java/com/kwan/shuyu/CuratorWatcherTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7dcdc24f06fdaf2b0dccc597b32e1164c4d5db9c --- /dev/null +++ b/src/test/java/com/kwan/shuyu/CuratorWatcherTest.java @@ -0,0 +1,127 @@ +package com.kwan.shuyu; + +import org.apache.curator.RetryPolicy; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.recipes.cache.*; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class CuratorWatcherTest { + private CuratorFramework client; + + /** + * 建立连接 + */ + @Before + public void testConnect() { + /* + * + * @param connectString 连接字符串。zk server 地址和端口 "192.168.149.135:2181,192.168.149.136:2181" + * @param sessionTimeoutMs 会话超时时间 单位ms + * @param connectionTimeoutMs 连接超时时间 单位ms + * @param retryPolicy 重试策略 + */ + /* //重试策略 + RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,10); + //1.第一种方式 + CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.149.135:2181", + 60 * 1000, 15 * 1000, retryPolicy);*/ + //重试策略 + RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10); + //2.第二种方式 + //CuratorFrameworkFactory.builder(); + client = CuratorFrameworkFactory.builder() + .connectString("192.168.149.135:2181") + .sessionTimeoutMs(60 * 1000) + .connectionTimeoutMs(15 * 1000) + .retryPolicy(retryPolicy) + .namespace("itheima") + .build(); + //开启连接 + client.start(); + } + + @After + public void close() { + if (client != null) { + client.close(); + } + } + + /** + * 演示 NodeCache:给指定一个节点注册监听器 + */ + @Test + public void testNodeCache() throws Exception { + //1. 创建NodeCache对象 + final NodeCache nodeCache = new NodeCache(client, "/app1"); + //2. 注册监听 + nodeCache.getListenable().addListener(new NodeCacheListener() { + @Override + public void nodeChanged() throws Exception { + System.out.println("节点变化了~"); + //获取修改节点后的数据 + byte[] data = nodeCache.getCurrentData().getData(); + System.out.println(new String(data)); + } + }); + //3. 开启监听.如果设置为true,则开启监听是,加载缓冲数据 + nodeCache.start(true); + while (true) { + } + } + + /** + * 演示 PathChildrenCache:监听某个节点的所有子节点们 + */ + @Test + public void testPathChildrenCache() throws Exception { + //1.创建监听对象 + PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/app2", true); + //2. 绑定监听器 + pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() { + @Override + public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception { + System.out.println("子节点变化了~"); + System.out.println(event); + //监听子节点的数据变更,并且拿到变更后的数据 + //1.获取类型 + PathChildrenCacheEvent.Type type = event.getType(); + //2.判断类型是否是update + if (type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)) { + System.out.println("数据变了!!!"); + byte[] data = event.getData().getData(); + System.out.println(new String(data)); + } + } + }); + //3. 开启 + pathChildrenCache.start(); + while (true) { + } + } + + /** + * 演示 TreeCache:监听某个节点自己和所有子节点们 + */ + @Test + public void testTreeCache() throws Exception { + //1. 创建监听器 + TreeCache treeCache = new TreeCache(client, "/app2"); + //2. 注册监听 + treeCache.getListenable().addListener(new TreeCacheListener() { + @Override + public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception { + System.out.println("节点变化了"); + System.out.println(event); + } + }); + //3. 开启 + treeCache.start(); + while (true) { + } + } +} \ No newline at end of file diff --git a/src/test/java/com/kwan/shuyu/LockTest.java b/src/test/java/com/kwan/shuyu/LockTest.java new file mode 100644 index 0000000000000000000000000000000000000000..133f3175207d378ea518c0dbcd45a9f460a43fb9 --- /dev/null +++ b/src/test/java/com/kwan/shuyu/LockTest.java @@ -0,0 +1,12 @@ +package com.kwan.shuyu; + +public class LockTest { + public static void main(String[] args) { + Ticket12306 ticket12306 = new Ticket12306(); + //创建客户端 + Thread t1 = new Thread(ticket12306, "携程"); + Thread t2 = new Thread(ticket12306, "飞猪"); + t1.start(); + t2.start(); + } +} \ No newline at end of file