zookeeper实现IdGenerator(多线程测试)

436 阅读2分钟

zookeeper系列之【IdGenerator,简单原理】

zookeeper系列之【IdGenerator,多线程测试】

zookeeper系列之【分布式锁】

zookeeper系列之【master选举】


原理

见:zookeeper实现IdGenerator(原理版本)

代码实现

public interface IGenerator {

	/**
	 * 生成器抽象方法
	 */
	long gen();
}
public class IdGenerator implements IGenerator {

	private ZkClient client; // 客户端持有
	private String nodePath; // 生成的顺序节点要放在哪个目录下

	private ArrayBlockingQueue<String> removeQueue;

	public IdGenerator(ZkClient client, String basePath, ArrayBlockingQueue<String> removeQueue) {
		this.client = client;
		this.nodePath = basePath.concat("/");
		this.removeQueue = removeQueue;

		// 初始化的时候,看看基础目录有没有,没有就来一个
		if (!client.exists(basePath)) {
			client.createPersistent(basePath, true);
		}
	}

	@Override
	public long gen() {
		// 生成临时节点,zookeeper会话关闭时,这些节点自动消失
		String fullPath = client.createEphemeralSequential(nodePath, null);
		removeQueue.add(fullPath);// 添加到删除队列(如果正式用的话,client会话是不会轻易close的,需要异步线程来删除)
		return Long.parseLong(fullPath.substring(fullPath.lastIndexOf("/") + 1));// 数字转换下
	}
}
public class TestClient {

	private static final int TOTAL_NUM = 10000;
	private static final int THREAD_NUM = 10;

	public static void main(String[] args) throws InterruptedException {
		// 删除队列
		ArrayBlockingQueue<String> removeQueue = new ArrayBlockingQueue<>(100000);

		// 线程池
		ExecutorService executorService = new ThreadPoolExecutor(10, 100, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(200), new ThreadFactory() {

			private final AtomicInteger threadNum = new AtomicInteger(0);

			@Override
			public Thread newThread(Runnable runnable) {
				return new Thread(runnable, "pool-1-thread-" + threadNum.incrementAndGet());
			}
		});

		CountDownLatch countDownLatch = new CountDownLatch(THREAD_NUM + 1);

		// 启动异步删除线程
		executorService.execute(new Runnable() {

			private ZkClient deleteClient = new ZkClient("localhost:2181,localhost:2182,localhost:2183", 5000, 5000, new SerializableSerializer());

			@Override
			public void run() {
				while (true) {// 只是演示
					String removeNode = removeQueue.poll();
					if (removeNode == null) {
						if (countDownLatch.getCount() == 1) {// 退出判断
							break;
						}
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						continue;
					}
					deleteClient.delete(removeNode);
				}
				countDownLatch.countDown();
			}
		});


		final long start = System.currentTimeMillis();
		for (int i = 0; i < THREAD_NUM; i++) {
			executorService.execute(new Runnable() {

				@Override
				public void run() {
					ZkClient client = new ZkClient("localhost:2181,localhost:2182,localhost:2183", 5000, 5000, new SerializableSerializer());
					IGenerator generator = new IdGenerator(client, "/mygen", removeQueue);
					for (int i = 0; i < TOTAL_NUM / THREAD_NUM; i++) { // 每个线程均匀分配下任务
						System.out.println(generator.gen());
					}
					client.close();// 关闭ZK会话
					countDownLatch.countDown();
					if (countDownLatch.getCount() == 1) {// 统计时间
						System.out.println("generator " + TOTAL_NUM + ", use time:" + (System.currentTimeMillis() - start));
					}
				}
			});
		}
		countDownLatch.await();

		// 关闭线程池
		executorService.shutdown();
	}
}