Zookeeper combat: custom distributed lock

rely

        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.9</version>
        </dependency>

        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.10</version>
        </dependency>

lock

public interface Lock {

    //获取锁
    void lock();

    //释放锁
    void unlock();

}
//借鉴AQS的实现,使用模板方法
public abstract class AbstractLock implements Lock {

    private static final Unsafe unsafe = getUnsafe();
    private static long stateOffset;
    //同步状态
    private volatile int state;

    public static final Unsafe getUnsafe() {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            Unsafe unsafe = (Unsafe) field.get(null);
            stateOffset = unsafe.objectFieldOffset
                    (AbstractLock.class.getDeclaredField("state"));
            return unsafe;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    //释放锁
    protected boolean tryUnLock() {
        throw new UnsupportedOperationException();
    }

    //唤醒
    protected void notifyLock() {
        throw new UnsupportedOperationException();
    }


    public  final void unlock() {
        if (tryUnLock()) {
            //线程唤醒
            notifyLock();
        }
    }

    protected final int getState() {
        return state;
    }

    protected final void setState(int newState) {
        state = newState;
    }

    //CAS,借鉴AtomicInteger实现
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

}

//分布式锁第一种实现:进程之间都通过监听同一个节点实现,这种容易引起羊群效应
public class ZkLock extends AbstractLock {
    private static final String PATH = "/lock";
    private static final ZkClient zkClient = ZkConnection.getConnection();
    private static final Lock lock = new ReentrantLock();

    public void lock() {
        //首先保证进程内线程的安全
        lock.lock();
        //获取分布式锁
        createNode();
    }

    @Override
    public boolean tryUnLock() {
        if (getState() == 0) {
            throw new RuntimeException("释放锁失败!");
        }
        try {
            return zkClient.delete(PATH);
        } catch (Exception e) {
            return false;
        }
    }


    @Override
    public void notifyLock() {
        setState(0);
        lock.unlock();
    }


    //创建节点
    public boolean createNode() {
        try {
            //创建的zk节点作为分布式锁
            zkClient.createEphemeral(PATH);
            //监听节点
            zkClient.subscribeDataChanges(PATH, new IZkDataListener() {
                public void handleDataChange(String s, Object o) {
                }

                //释放锁的时候唤醒其他线程
                public void handleDataDeleted(String s) {
                    notifyLock();
                }
            });
            if (compareAndSet(0, 1)) {
                return true;
            }

        } catch (Exception e) {
            return false;
        }
        return false;
    }

}

test

public class OrderNumGenerator {

    private OrderNumGenerator() {
    }

    //全局订单id
    public static int count = 0;

    //生成订单ID
    public static String getNumber() {
        SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        return simpt.format(new Date()) + "-" + (++count);
    }

}
//zk连接
public class ZkConnection {
    // zk连接地址
    private static final String CONNECTSTRING = "127.0.0.1:2181";
    private static final int connectionTimeout = 50000;
    private static final int sessionTimeout = 50000;

    private ZkConnection() {
    }

    private static class ZkConnectionBuilder {
        private final static ZkClient zkConnection = new ZkClient(CONNECTSTRING, sessionTimeout, connectionTimeout);
    }

    public static final ZkClient getConnection() {
        return ZkConnectionBuilder.zkConnection;
    }

}
//订单生成--模拟并发
public class OrderService implements Runnable {

    public Lock lock = new ZkLock();

    public void run() {
        try {
            lock.lock();

            String number = OrderNumGenerator.getNumber();
            System.out.println("获取订单号...." + number);
        } finally {

            lock.unlock();
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(new OrderService()).start();
        }
    }


}

result

Insert picture description here

Guess you like

Origin blog.csdn.net/qq_28822933/article/details/86301659