五.Curator实现分布式锁

        InterProcessMutex:全局可重入锁,客户端都可以请求锁,并且同一个客户端在拥有锁的同时,可以多次获取,不会被阻塞。客户端在拥有锁的同时,可以多次获取,不会被阻塞。

package DistributeLock;

import java.util.concurrent.TimeUnit;

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

/**
 * 这个类负责请求锁,使用资源,释放锁这个完整的访问流程
 * */
public class ExampleClientThatLocks
{
    private final InterProcessMutex lock;//全局可重入锁
    private final FakeLimitedResource resource;//共享资源
    private final String clientName;
    public ExampleClientThatLocks(CuratorFramework client,String lockPath, FakeLimitedResource resource, String clientName)
    {
        this.lock = new InterProcessMutex(client, lockPath);
        this.resource = resource;
        this.clientName = clientName;
    }
    public void doWork(long time,TimeUnit unit) throws Exception{
        //尝试获取锁,如果无法获取锁,抛出异常
        if(!lock.acquire(time, unit)){
            throw new IllegalStateException(clientName + "不能获取锁");
        }
        System.out.println(clientName +"获得了锁");
        if(!lock.acquire(time, unit)){
            throw new IllegalStateException(clientName + "不能再次获取锁");
        }
        System.out.println(clientName +"再次获得了锁(重入功能)");
        try{
            resource.use();
        }finally{
            System.out.println(clientName + "释放了锁");
            lock.release();
            lock.release();
        }
        
    }
    
    
}
package DistributeLock;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 模拟共享资源,这个资源期望只能单线程访问,否则会有并发问题(走到抛异常的逻辑)
 * <br>
 */
public class FakeLimitedResource {
    private final AtomicBoolean inUse = new AtomicBoolean(false);

    public void use() throws InterruptedException {
        /**
         * inUse.compareAndSet(false, true)表示:先检测当前值是否为false,如果为false,就更新为true
         * 如果多个线程执行这个方法,在无锁的情况下,由于下面睡了一段时间,所以有些线程会走到抛异常的地方
         */
        if (!inUse.compareAndSet(false, true)) { 
            throw new IllegalStateException("Needs to be used by one client at a time");
        }
        try {
            Thread.sleep(5000);
        } finally {
            inUse.set(false);
        }
    }
    public void read(){
        System.out.println(inUse.get());
    }
}
package DistributeLock;

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

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.test.TestingServer;
import org.apache.curator.utils.CloseableUtils;
/**
 *可重入锁InterProcessMutex例子 
 *
 */
public class InterProcessMutexExample
{   
    private static final String PATH = "/examples/locks";
    public static void main(String[] args) throws Exception
    {
        //共享资源
        final FakeLimitedResource resource = new FakeLimitedResource();
        //有50个线程的线程池
        ExecutorService service = Executors.newFixedThreadPool(10);
        
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 5);
       
        //10个线程,模拟10个客户端
        for(int i=0;i<10;++i){
            final int index = i;
            Callable<Void> task = new Callable<Void>()
            {

                public Void call() throws Exception
                {
                    //2.通过工厂建立连接
                    CuratorFramework client = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181")
                            .sessionTimeoutMs(5000)
                            .retryPolicy(retryPolicy)
                            .build();
                    try
                    {
                        client.start();
                        ExampleClientThatLocks example = new ExampleClientThatLocks(client, PATH, resource,"client" + index);
                        //每个客户端重复5次任务
                        for(int j=0;j<5;++j){
                            example.doWork(10, TimeUnit.SECONDS);
                        }
                    }
                    catch (Exception e)
                    {
                       e.printStackTrace();
                    }finally{
                        CloseableUtils.closeQuietly(client);//关闭该客户端
                    }
                    
                    return null;
                }
            };
            service.submit(task);
        }
        service.shutdown();
        
    }
}

  代码也很简单,生成10个client, 每个client重复执行5次 请求锁–访问资源–释放锁的过程。每个client都在独立的线程中。结果可以看到,锁是随机的被每个客户端实例排他性的使用。既然是可重用的,你可以在一个线程中多次调用acquire,在线程拥有锁时它总是返回true。 

  你不应该在多个线程中用同一个InterProcessMutex,你可以在每个线程中都生成一个InterProcessMutex实例,它们的path都一样,这样它们可以共享同一个锁。


InterProcessSemaphoreMutex:不可重入锁
  这个锁和上面的相比,就是少了Reentrant的功能,也就意味着它不能在同一个线程中重入。 这个类是InterProcessSemaphoreMutex。使用方法和上面的类类似。

  我们将上面的例子修改一下,测试一下它的重入,修改ExampleClientThatLocks.doWork,连续两次acquire。现在第二次acquire进不去了。

package curatorExample.DistributeLock;


import java.util.concurrent.TimeUnit;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;
/**
 * 测试不可重入锁
 * 这个类负责请求锁,使用资源,释放锁这个完整的访问流程
 * */
public class ExampleClientThatLocks2
{
    private final InterProcessSemaphoreMutex lock;//全局可重入锁
    private final FakeLimitedResource resource;//共享资源
    private final String clientName;
    public ExampleClientThatLocks2(CuratorFramework client,String lockPath, FakeLimitedResource resource, String clientName)
    {
        this.lock = new InterProcessSemaphoreMutex(client, lockPath);//不可重入的锁
        this.resource = resource;
        this.clientName = clientName;
    }
    public void doWork(long time,TimeUnit unit) throws Exception{
        //尝试获取锁,如果无法获取锁,抛出异常
        if(!lock.acquire(time, unit)){
            throw new IllegalStateException(clientName + "不能获取锁");
        }
        System.out.println(clientName +"获得了锁");
        //现在这里不能重入了
        if(!lock.acquire(time, unit)){
            throw new IllegalStateException(clientName + "不能再次获取锁");
        }
        System.out.println(clientName +"再次获得了锁(重入功能)");
        try{
            resource.use();
        }finally{
            System.out.println(clientName + "释放了锁");
            lock.release();
            lock.release();
        }
        
    }
}


InterProcessReadWriteLock:可重入读写锁

  类似JDK的ReentrantReadWriteLock. 一个读写锁管理一对相关的锁。 一个负责读操作,另外一个负责写操作。读操作在写锁没被使用时可同时由多个进程使用,而写锁使用时不允许读 (阻塞)。 此锁是可重入的。一个拥有写锁的线程可重入读锁,但是读锁却不能进入写锁。 这也意味着写锁可以降级成读锁, 比如请求写锁 —>读锁 —->释放写锁。从读锁升级成写锁是不成的。

  主要由两个类实现:

         InterProcessReadWriteLock
         InterProcessLock

  使用时首先创建一个InterProcessReadWriteLock实例,然后再根据你的需求得到读锁或者写锁, 读写锁的类型是InterProcessLock。 
   public InterProcessLock readLock()
        public InterProcessLock writeLock()

package curatorExample.DistributeLock;


import java.util.Random;
import java.util.concurrent.TimeUnit;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;


public class ExampleClientReadWriteLocks
{
    private final InterProcessReadWriteLock lock;
    private final InterProcessLock readLock;
    private final InterProcessLock writeLock;
    private final FakeLimitedResource resource;
    private final String clientName;
    public ExampleClientReadWriteLocks(CuratorFramework client, String lockPath, FakeLimitedResource resource, String clientName) {
        this.resource = resource;
        this.clientName = clientName;
        lock = new InterProcessReadWriteLock(client, lockPath);
        readLock = lock.readLock();
        writeLock = lock.writeLock();
    }
    public void doWork(long time,TimeUnit unit) throws Exception{
        Random rand = new Random();
        int random_data = rand.nextInt();
        try{
            if(random_data %10 == 0){
                //尝试获取写锁,
                if(!writeLock.acquire(time, unit)){
                    throw new IllegalStateException(clientName + "不能获得写锁");
                }
                System.out.println(clientName + " 获得了写锁");  
                resource.use();  
            }else{
                //尝试获取读锁
                if(!readLock.acquire(time, unit)){
                    throw new IllegalStateException(clientName + "不能获得读锁");
                }
                System.out.println(clientName + " 获得了读锁");
                resource.read();
                
            } 
        }finally{
            System.out.println(clientName + " 释放锁");
            if(writeLock.isAcquiredInThisProcess())
                writeLock.release(); 
            if(readLock.isAcquiredInThisProcess())
                readLock.release(); 
        }
        
        
        
        
    }
}

package curatorExample.DistributeLock;



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

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

public class InterProcessReadWriteLockExample
{
    private static final String PATH = "/examples/locks";
    public static void main(String[] args) throws Exception
    {
        //共享资源
        final FakeLimitedResource resource = new FakeLimitedResource();
        //有10个线程的线程池
        ExecutorService service = Executors.newFixedThreadPool(10);
        
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 5);
       
        //10个线程,模拟10个客户端
        for(int i=0;i<10;++i){
            final int index = i;
            Callable<Void> task = new Callable<Void>()
            {

                public Void call() throws Exception
                {
                    //2.通过工厂建立连接
                    CuratorFramework client = CuratorFrameworkFactory.builder().connectString("192.168.10.110:2181,192.168.10.111:2181,192.168.10.112:2181")
                            .sessionTimeoutMs(5000)
                            .retryPolicy(retryPolicy)
                            .build();
                    try
                    {
                        client.start();
                        ExampleClientReadWriteLocks example = new ExampleClientReadWriteLocks(client, PATH, resource,"client" + index);
                        //每个客户端重复5次任务
                        for(int j=0;j<5;++j){
                            example.doWork(10, TimeUnit.SECONDS);
                        }
                    }
                    catch (Exception e)
                    {
                       e.printStackTrace();
                    }finally{
                        CloseableUtils.closeQuietly(client);//关闭该客户端
                    }
                    
                    return null;
                }
            };
            service.submit(task);
        }
        service.shutdown();
    }
}




猜你喜欢

转载自blog.csdn.net/js54100804/article/details/78885081