通过自旋自定义一个分布式锁

1、定义锁类

package com.xiangwen.day3;

import java.util.concurrent.atomic.AtomicBoolean;

public class MyReentLock {
    private static AtomicBoolean atomicBoolean = new AtomicBoolean(false);
    private static String currentClient = "default";

    public static void tryLock(long waitTime, String clientUuid) throws InterruptedException {
        long start = System.currentTimeMillis();
        while (true) {
            if (atomicBoolean.compareAndSet(false, true)) {
                currentClient = clientUuid;
                break;
            } else {
                long end = System.currentTimeMillis();
                if ((end - start) >= waitTime) {
                    System.out.println("超过最大等待时间了"+(end-start));
                    break;
                }
            }
        }

    }

    public static void unLock(String uuid) {
        if (currentClient.equals(uuid)) {
            atomicBoolean.compareAndSet(true, false);
        }
    }

}

  2、测试类

package com.xiangwen.day3;

import java.util.UUID;

public class MyReentLockClientToTest {
    private static int ticket = 50;

    public static void main(String[] args) {
        //模拟100个客户端去远程调用,调用会传送客户端uuid
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                long start=System.currentTimeMillis();
                String uuid = UUID.randomUUID().toString();
                try {
                    MyReentLock.tryLock(20000, uuid);
                    if (ticket > 0) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        System.out.println(Thread.currentThread() + "剩余票数" + (--ticket));
                    } else {
                        System.out.println("票卖光了");
                    }
                    MyReentLock.unLock(uuid);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                long end=System.currentTimeMillis();
                System.out.println(Thread.currentThread()+"耗时"+(end-start));
            }).start();
        }
    }
}

  运行截图

 

 

 

 

 结论:总耗时是15100ms,虽然有50个线程模拟正常卖票逻辑每次消耗100ms,本来应该是50*100,但实际因为有线程休眠,用户态和内核态切换消多消耗了200ms,实际每次耗时平均是300多ms,然后最终是300*50=1500ms

如果按照下面换成自旋,50个工作线程每个节省100ms,实际节省了5秒,能发现线程任务刚开始很慢,后来越来越快,看到线程标号能发现,当前面任务结束后,后面用的线程看着是复用的之前的线程

 

posted @ 2023-07-25 00:33  傲云萧雨  阅读(21)  评论(0编辑  收藏  举报