轮子是如何实现的?参照Hutool例子

56

分布式唯一ID工具

1.雪花算法

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * 雪花算法的工具类: 雪花算法一共分为五个部分
 *
 * <p>第一部分:是1bit,就是一个0,没有任何意义。
 *
 * <p>第二部分:是41bit的时间戳。
 *
 * <p>第三部分:是5bit,机房id。
 *
 * <p>第四部分:是5bit,机器id。
 *
 * <p>第五部分:是12bit,表示序列号 就是这个机房这个机器上,这一毫秒,同时产生的雪花算法的值的序列号。
 *
 * <p>这说明雪花算法单机一毫秒并发2048.
 */
@Component
public class SnowFlakeUtil {

  /** 机器id */
  @Value("${snowflake.worker:0}")
  private long workerId;

  /** 机房id */
  @Value("${snowflake.dataCenterId:0}")
  private long dataCenterId;

  /** 序号 */
  private long sequence;

  /**
   * 雪花算法时间的起点 它其实就是当初算法创立者创立此算法的那个时间点。
   *
   * <p>因为时间戳只有41位,因此当此算法运行69年左右的时候,时间就会重复。
   *
   * <p>twepoch可以以现在的时间为值
   *
   * <p>软件开发,设计的程序,需要保证多长时间不出问题呢?20年。
   */
  private long twepoch = 1627462055200L;

  /**
   * 机房id与机器id都是5位
   *
   * <p>bit=位
   *
   * <p>byte=字节=8位=8bit
   */
  private long workerIdBits = 5L;

  private long dataCenteridBits = 5L;

  /**
   * 求n为二进制的最大值,怎么求? 2^n 1<<n - 1
   *
   * <p>最好求数据不需要更多bit。
   *
   * <p>-1^(-1<<n) => n个1
   *
   * <p>原码:1000 0001 反码:1111 1110 补码:1111 1111
   *
   * <p>左移3位:1111 1000 ^ 1111 1111 --------------- 0000 0111
   */

  /** 机器号的最大值 */
  private long maxWorkId = -1L ^ (-1L << workerIdBits);

  /** 机房id的最大值 */
  private long maxDataCenterId = -1L ^ (-1L << dataCenteridBits);

  /** 序列号的长度 */
  private long sequenceBits = 12L;

  /** 序列号的最大值 */
  private long maxSequence = -1L ^ (-1L << sequenceBits);

  /** 机器id左移12位数 */
  private long workerIdShift = sequenceBits;

  /** 机房id左移17位数 */
  private long dataCenterIdShift = sequenceBits + workerIdBits;

  /** 时间戳左移22位数 */
  private long timestampShift = sequenceBits + workerIdBits + dataCenteridBits;

  /** 总体的记录的时间 */
  private long lastTimestamp = -1L;

  /** 获取时间的方法 */
  private long time() {
    return System.currentTimeMillis();
  }

  /** 获取一个新的时间 */
  private long nextTime(long lastTimestamp) {
    long timestamp = time();
    while (timestamp <= lastTimestamp) {
      timestamp = time();
    }
    return timestamp;
  }

  /** 生成与拼装雪花算法 */
  public synchronized long nextId() {
    // 获取当前时间
    long timestamp = time();
    // 和上一次时间比较
    if (timestamp < lastTimestamp) {
      return -1;
    }
    // 1毫秒内的并发
    if (lastTimestamp == timestamp) {
      sequence = (sequence + 1) & maxSequence;
      if (sequence == 0) {
        // 获取一个新的时间,因为这一毫秒sequence已经最大了
        timestamp = nextTime(lastTimestamp);
      }
    } else {
      sequence = 0;
    }
    // 记录这一次生成雪花算法id的时间
    lastTimestamp = timestamp;
    // 拼装雪花算法的id
    return ((timestamp - twepoch) << timestampShift)
        | (dataCenterId << dataCenteridBits)
        | (workerId << workerIdBits)
        | (sequence);
  }
}

异步工具

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/** 异步请求的工具类 */
public class AsyncBatchCallUtil {

  /** 对外界提供方法 */
  public static void execute(Runnable task) {
    executorService.execute(task);
  }

  /** 线程池服务 */
  private static ExecutorService executorService;

  static {
    // 核心线程数
    int corePoolSize = 5;
    // 最大线程数
    int maxPoolSize = 10;
    // 时间
    long keepAliveTime = 10;
    // 时间单位
    TimeUnit unit = TimeUnit.SECONDS;
    // 队列
    BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue(6);
    // 默认工厂
    ThreadFactory threadFactory = new UserThreadFactory("qianfeng");
    // 拒绝策略
    RejectedExecutionHandler handler = new MyRejectPolicy();
    // 实例化线程池
    executorService =
        new ThreadPoolExecutor(
            corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
  }

  /** 拒绝策略 */
  static class MyRejectPolicy implements RejectedExecutionHandler {

    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
      System.out.println(AsyncBatchCallUtil.class.getName() + "的线程队列已经满了");
    }
  }

  /** 线程工厂 */
  static class UserThreadFactory implements ThreadFactory {

    private final String namePrefix;
    private final AtomicInteger nextId = new AtomicInteger(1);

    UserThreadFactory(String groupName) {
      namePrefix = "From " + UserThreadFactory.class.getName() + "-" + groupName + "-";
    }

    @Override
    public Thread newThread(Runnable r) {
      String name = namePrefix + nextId.getAndIncrement();
      Thread thread = new Thread(null, r, name);
      return thread;
    }
  }
}
    // 使用封装好的线程池执行我们的异步逻辑
    AsyncBatchCallUtil.execute(
        () -> {
          //gifService.createGif(targetFile, fileName, url);
        });

同步工具


import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/** 同步调用的工具类 内部要封装线程池与CountDownLatch */
public class SyncBatchCallUtil {
  /** 线程池 */
  private static ExecutorService executorService;

  static {
    // 核心线程数
    int corePoolSize = 5;
    // 最大线程数
    int maxPoolSize = 10;
    // 时间
    long keepAliveTime = 10;
    // 时间单位
    TimeUnit unit = TimeUnit.SECONDS;
    // 队列
    BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue(6);
    // 默认工厂
    ThreadFactory threadFactory = new UserThreadFactory("qianfeng-countdownlatch");
    // 拒绝策略
    RejectedExecutionHandler handler = new MyRejectPolicy();
    // 实例化线程池
    executorService =
        new ThreadPoolExecutor(
            corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
  }
  /** 拒绝策略 */
  static class MyRejectPolicy implements RejectedExecutionHandler {

    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
      System.out.println(AsyncBatchCallUtil.class.getName() + "的线程队列已经满了");
    }
  }

  /** 线程工厂 */
  static class UserThreadFactory implements ThreadFactory {

    private final String namePrefix;
    private final AtomicInteger nextId = new AtomicInteger(1);

    UserThreadFactory(String groupName) {
      namePrefix =
          "From " + AsyncBatchCallUtil.UserThreadFactory.class.getName() + "-" + groupName + "-";
    }

    @Override
    public Thread newThread(Runnable r) {
      String name = namePrefix + nextId.getAndIncrement();
      Thread thread = new Thread(null, r, name);
      return thread;
    }
  }

  /** 自定义任务类 */
  public abstract static class Task implements Runnable {
    /** 任务调度的方法 */
    public abstract void exe();

    /** 内部封装CountDownLatch */
    private CountDownLatch countDownLatch;

    public void setCountDownLatch(CountDownLatch countDownLatch) {
      this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
      // 先执行任务0
      try {
        exe();
      } catch (Exception e) {
        e.printStackTrace();
      } finally {
        // 再让计数器-1
        countDownLatch.countDown();
      }
    }
  }

  /** 创建一组任务 */
  private static boolean createTasks(Task[] tasks) {
    // 给这组任务实例一个CountDownLatch
    // 注意:是一组任务对应一个CountDownLatch
    // 有多少个任务,计数器就是多少,所以构造方法参数为tasks.length
    CountDownLatch countDownLatch = new CountDownLatch(tasks.length);
    // 给每一个任务设定相同的CountDownLatch
    for (int i = 0; i < tasks.length; i++) {
      tasks[i].setCountDownLatch(countDownLatch);
    }
    // 每一个task类型其实都是Runnable类型,它应该用线程池来执行。
    for (int i = 0; i < tasks.length; i++) {
      // 启动每一个任务
      executorService.execute(tasks[i]);
    }
    // 卡住当前线程
    try {
      countDownLatch.await();
    } catch (InterruptedException e) {
      e.printStackTrace();
      return false;
    }
    return true;
  }

  /**
   * 给外界提供可调用的方法
   *
   * @param tasks 指定一组任务
   * @return 这组任务是否创建成功
   */
  public static boolean batch(Task... tasks) {
    return createTasks(tasks);
  }
}
/** 测试同步调用聚合接口的工具类 */
public class TestSyncBatchUtil {
  public static void main(String[] args) {
    long startTime = System.currentTimeMillis();

    SyncBatchCallUtil.batch(
        new Task() {
          @Override
          public void exe() {
            try {
              Thread.sleep(3000);
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
            // userClient.search("userId");
          }
        },
        new Task() {
          @Override
          public void exe() {
            try {
              Thread.sleep(5000);
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
        },
        new Task() {
          @Override
          public void exe() {
            try {
              Thread.sleep(4000);
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
        });

    System.out.println("任务总耗时为:" + (System.currentTimeMillis() - startTime) + "毫秒。");
  }
}

缓存工具

1.LRU Cache

import java.lang.ref.SoftReference;

/**
 * 内存缓存组件 LRU算法
 *
 * <p>1、使用LRU算法进行内存淘汰。
 *
 * <p>2、使用软引用,来避免因为LRU算法导致原本的SSM模型内存不够用。
 */
public class CacheUtil {

  /** 链表的头 */
  private Node top;
  /** 链表的尾 */
  private Node bottom;
  /** 缓存区的大小(缓存对象的个数) */
  private Integer size;
  /** 当前元素个数 */
  private int length;

  public CacheUtil(int size) {
    this.size = size;
  }

  public Object get(String key) {
    synchronized (size) {
      //  1-->2-->3
      // 删除,头插。
      if (length == 0) {
        return null;
      } else {
        // 链表版的for循环标准形式
        for (Node p = top; p != null; p = p.next) {
          if (p.key.equals(key)) {
            // 找到了
            if (p == top) {
              Object object = p.value.get();
              if (object == null) {
                // 软引用的对象被回收了
                top = top.next;
                length--;
                return null;
              } else {
                return object;
              }
            }
            // 找到的元素并不是头结点
            if (p.next != null) {
              // 找到的这个元素不是头也不是尾
              p.next.prev = p.prev;
              p.prev.next = p.next;
              Object object = p.value.get();
              if (object == null) {
                length--;
                return null;
              } else {
                p.next = top;
                top.prev = p;
                top = p;
                p.prev = null;
                return object;
              }
            } else {
              // 找到的元素是链表的尾部
              bottom = bottom.prev;
              bottom.next = null;
              Object object = p.value.get();
              if (object == null) {
                length--;
                return null;
              } else {
                p.next = top;
                top.prev = p;
                top = p;
                p.prev = null;
                return object;
              }
            }
          }
        }
      }
    }
    return null;
  }

  public void put(String key, Object value) {
    synchronized (size) {
      if (length > 0) {
        // 先查就可以了
        for (Node p = top; p.next != null; p = p.next) {
          if (key.equals(p.key)) {
            // 找到了
            // 把p删了
            if (p == top) {
              top = top.next;
            } else if (p == bottom) {
              bottom = bottom.prev;
            } else {
              p.next.prev = p.prev;
              p.prev.next = p.next;
            }
            length--;
          }
        }
      }
      // 实例了一个软引用
      SoftReference<Object> softReference = new SoftReference<Object>(value);
      // 头插尾删
      if (length == 0) {
        top = new Node();
        bottom = top;
        top.key = key;
        top.value = softReference;
        length++;
        return;
      } else if (length <= size) {
        // 头插
        Node temp = new Node();
        temp.next = top;
        top.prev = temp;
        temp.key = key;
        temp.value = softReference;
        top = temp;
        if (length < size) {
          length++;
        }
      }
      if (length >= size) {
        // 尾删
        bottom = bottom.prev;
        bottom.next = null;
      }
    }
  }
  /** 双向链表实现 定义双向链表 */
  private class Node {
    String key;
    SoftReference<Object> value;
    Node prev;
    Node next;
  }
}
 /** 测试 */
  public static void main(String[] args) {
    CacheUtil cacheUtil = new CacheUtil(5);
    for (int i = 1; i <= 5; i++) {
      cacheUtil.put("a" + i, "" + i);
    }
    System.out.println(cacheUtil.get("a2"));

    // 下面代码执行,出去的是谁?
    cacheUtil.put("a6", "6");
    System.out.println(cacheUtil.get("a1"));
    cacheUtil.put("a7", "7");
    System.out.println(cacheUtil.get("a3"));
    System.out.println(cacheUtil.get("a2"));
  }

Spring上下文工具

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/** spring上下文的工具类 */
@Component
public class SpringContextUtil implements ApplicationContextAware {

  /** 获取应用程序上下文对象 获取IoC容器内部的对象的时候,要结合上下文对象获取 */
  private static ApplicationContext applicationContext;

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    SpringContextUtil.applicationContext = applicationContext;
  }

  /** 调用spring上下文,获取容器内对应的类型的对象 */
  public static <T> T getBean(Class<T> clazz) {
    return applicationContext.getBean(clazz);
  }
}
MessageDao  messageDao = SpringContextUtil.getBean(MessageDao.class);