基于Zookeeper的分布式锁实现

基于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下的目录



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值