基于Zookeeper的分布式锁实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kwu_ganymede/article/details/73865499

基于zk的分布式锁实现


1、pom依赖的包

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.ganymede</groupId>
	<artifactId>zk-distributed-lock</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>zk-distributed-lock</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<zookeeper.version>3.4.5</zookeeper.version>
		<curator.version>2.9.0</curator.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.zookeeper</groupId>
			<artifactId>zookeeper</artifactId>
			<version>${zookeeper.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.curator</groupId>
			<artifactId>curator-recipes</artifactId>
			<version>${curator.version}</version>
		</dependency>
	</dependencies>
</project>


2、操作zk的工厂类

package com.ganymede.lock;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;

/**
 * 操作zk的工厂类
 * 
 * @author Ganymede
 *
 */
public class ZookeeperFactory {

	private static final String connectString = "spark1:2181,spark2:2181,spark3:2181";

	public static CuratorFramework curatorClient = null;

	public static CuratorFramework createClient() {
		RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
		if (curatorClient != null) {
			return curatorClient;
		}
		curatorClient = CuratorFrameworkFactory.builder().connectString(connectString).retryPolicy(retryPolicy)
				.sessionTimeoutMs(1000).connectionTimeoutMs(1000).build();
		curatorClient.start();
		return curatorClient;
	}

}




3、模拟多线程时,出问题的程序代码块

package com.ganymede.lock;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 模拟多线程时,出问题的程序代码块
 * @author Ganymede
 *
 */
public class LimitedResource {
	private final AtomicBoolean ab = new AtomicBoolean(false);

	public void useResource() throws InterruptedException {
		if (!ab.compareAndSet(false, true)) {
			throw new IllegalArgumentException("线程" + Thread.currentThread().getId() + "非法操作!");
		}
		System.out.println("线程" + Thread.currentThread().getId() + "正在操作");
		Thread.sleep(1000);
		ab.set(false);

	}

}

4、zk分布式锁实现,不可重用锁

package com.ganymede.lock;

import java.util.concurrent.TimeUnit;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;

/**
 * 不可重用锁 
 * 同一线程,不能两次调用acquire 
 * 不会同时拥有两把锁
 * 
 * @author Ganymede
 *
 */
public class ZkDistributedLock {

	private InterProcessSemaphoreMutex lock;
	private LimitedResource resource;
	private String threadName;

	public ZkDistributedLock(CuratorFramework client, String path, LimitedResource resource, String threadName) {
		lock = new InterProcessSemaphoreMutex(client, path);
		this.resource = resource;
		this.threadName = threadName;
	}

	public void execute(long time, TimeUnit unit) {
		// acquire(time, unit),获取到了锁返回true,有超时机制,在unit为单位的time中还没获取到锁,就超时了
		try {
			while (!lock.acquire(time, unit)) {
				System.out.println("线程" + threadName + Thread.currentThread().getId() + "正在着急等待获取锁");
			}

			System.out.println("线程" + threadName + Thread.currentThread().getId() + "获取锁");
			resource.useResource();
			System.out.println("线程" + threadName + Thread.currentThread().getId() + "释放锁");

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				// release()释放锁,获取到锁之后,完成了任务,必须释放
				lock.release();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}

}


5、模似多线程并发操作

package com.ganymede.lock;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.apache.curator.framework.CuratorFramework;


/**
 * 模似多线程并发操作
 * 
 * @author Ganymede
 *
 */
public class ZkDistributedLockTest {

	public static void main(String[] args) throws InterruptedException {
		final LimitedResource lr = new LimitedResource();
		final String path = "/ganymede/lock";
		ExecutorService service = Executors.newFixedThreadPool(7);

		for (int i = 0; i < 7; i++) {
			Callable<Void> task = new Callable<Void>() {
				@Override
				public Void call() throws Exception {
					CuratorFramework client = ZookeeperFactory.createClient();
					ZkDistributedLock lock = new ZkDistributedLock(client, path, lr, "thread");
					lock.execute(5, TimeUnit.SECONDS);

					return null;
				}
			};
			service.submit(task);
		}

		service.shutdown();
		service.awaitTermination(25, TimeUnit.MINUTES);

	}

}


6、运行结果

线程thread14获取锁
线程14正在操作
线程thread14释放锁
线程thread15获取锁
线程15正在操作
线程thread15释放锁
线程thread16获取锁
线程16正在操作
线程thread16释放锁
线程thread12获取锁
线程12正在操作
线程thread12释放锁
线程thread11获取锁
线程11正在操作
线程thread17正在着急等待获取锁
线程thread13正在着急等待获取锁
线程thread11释放锁
线程thread17获取锁
线程17正在操作
线程thread17释放锁
线程thread13获取锁
线程13正在操作
线程thread13释放锁
多线程抢占资源下,只有一个线程可以获得一次锁,并且不能两次获取。


7、查看zk下的目录



猜你喜欢

转载自blog.csdn.net/kwu_ganymede/article/details/73865499