通过自旋自定义一个分布式锁
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秒,能发现线程任务刚开始很慢,后来越来越快,看到线程标号能发现,当前面任务结束后,后面用的线程看着是复用的之前的线程