jdk下载镜像

下载地址一
华为镜像源

1. maven本地安装jar包命令

  1. mvn install:install-file -DgroupId=org.apache.phoenix -DartifactId=phoenix-client -Dversion=4.14.0-cdh5.14.2 -Dpackaging=jar -Dfile=E:\phoenix-core-4.14.0-cdh5.14.2.jar

3. 查找占用端口号的进程

  1. netstat -ano|findstr 8080
  2. #关闭指定pid的进程
  3. taskkill /F /pid "pid"

4. nvm安装

  1. 修改settings镜像位置

    1. root: D:\nvm
    2. path: D:\nodejs
    3. node_mirror: https://npm.taobao.org/mirrors/node/
    4. npm_mirror: https://npm.taobao.org/mirrors/npm/
  2. npm/yarn设置淘宝镜像 将npm修改成yarn即可

    1. npm config set registry " https://registry.npm.taobao.org "
    2. npm config set sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
    3. npm config set phantomjs_cdnurl=https://npm.taobao.org/mirrors/phantomjs/
    4. npm config set phantomjs_cdnurl=https://npm.taobao.org/mirrors/phantomjs/

    5. 添加开机启动程序

    进入目录 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp
    将应用的的快捷方式放在里面就可以

    6.Hutool雪花算法实现记录

    Twitter的Snowflake 算法

    分布式系统中,有一些需要使用全局唯一ID的场景,有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。
    snowflake的结构如下(每部分用-分开):
    符号位(1bit)- 时间戳相对值(41bit)- 数据中心标志(5bit)- 机器标志(5bit)- 递增序号(12bit)
    0 - 0000000000 0000000000 0000000000 00000000000 - 00000 - 00000 - 000000000000
    第一位为未使用(符号位0表示正数),
    接下来的41位为毫秒级时间(41位的长度可以使用69年) (1L << 41) / (1000L 60 60 24 365) = 69年;
    然后是5位datacenterId和5位workerId(10位的长度最多支持部署1<<10=1024个节点)
    最后12位是毫秒内的计数(12位的计数顺序号支持每个节点每毫秒产生1<<12 =4096个ID序号)

    代码记录

    ```java /**

    • 构造,使用自动生成的工作节点ID和数据中心ID */ public Snowflake() { this(IdUtil.getWorkerId(IdUtil.getDataCenterId(MAX_DATA_CENTER_ID), MAX_WORKER_ID)); }

/**

  1. * @param epochDate 初始化时间起点(null表示默认起始日期),后期修改会导致id重复,如果要修改连workerId dataCenterId,慎用
  2. * @param workerId 工作机器节点id
  3. * @param dataCenterId 数据中心id
  4. * @param isUseSystemClock 是否使用{@link SystemClock} 获取当前时间戳
  5. * @param timeOffset 允许时间回拨的毫秒数
  6. * @since 5.7.3
  7. */
  8. public Snowflake(Date epochDate, long workerId, long dataCenterId, boolean isUseSystemClock, long timeOffset) {
  9. if (null != epochDate) {
  10. this.twepoch = epochDate.getTime();
  11. } else{
  12. // Thu, 04 Nov 2010 01:42:54 GMT
  13. this.twepoch = DEFAULT_TWEPOCH;
  14. }
  15. if (workerId > MAX_WORKER_ID || workerId < 0) {
  16. throw new IllegalArgumentException(StrUtil.format("worker Id can't be greater than {} or less than 0", MAX_WORKER_ID));
  17. }
  18. if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {
  19. throw new IllegalArgumentException(StrUtil.format("datacenter Id can't be greater than {} or less than 0", MAX_DATA_CENTER_ID));
  20. }
  21. this.workerId = workerId;
  22. this.dataCenterId = dataCenterId;
  23. this.useSystemClock = isUseSystemClock;
  24. this.timeOffset = timeOffset;
  25. }
  1. ```java
  2. /**
  3. * 获取数据中心ID<br>
  4. * 数据中心ID依赖于本地网卡MAC地址。
  5. * <p>
  6. * 此算法来自于mybatis-plus#Sequence
  7. * </p>
  8. *
  9. * @param maxDatacenterId 最大的中心ID
  10. * @return 数据中心ID
  11. * @since 5.7.3
  12. */
  13. public static long getDataCenterId(long maxDatacenterId) {
  14. long id = 1L;
  15. //获取本地的一个mac地址 字节6位
  16. final byte[] mac = NetUtil.getLocalHardwareAddress();
  17. if (null != mac) {
  18. //取mac地址的倒数第二位的二进制作为低八位,倒数第一位作为高八位
  19. //相加之后右移六位,得到结果对最大的中心ID进行取余
  20. id = ((0x000000FF & (long) mac[mac.length - 2])
  21. | (0x0000FF00 & (((long) mac[mac.length - 1]) << 8))) >> 6;
  22. id = id % (maxDatacenterId + 1);
  23. }
  24. return id;
  25. }
  26. /**
  27. * 获取机器ID,使用进程ID配合数据中心ID生成<br>
  28. * 机器依赖于本进程ID或进程名的Hash值。
  29. *
  30. * <p>
  31. * 此算法来自于mybatis-plus#Sequence
  32. * </p>
  33. *
  34. * @param datacenterId 数据中心ID
  35. * @param maxWorkerId 最大的机器节点ID
  36. * @return ID
  37. * @since 5.7.3
  38. */
  39. public static long getWorkerId(long datacenterId, long maxWorkerId) {
  40. final StringBuilder mpid = new StringBuilder();
  41. mpid.append(datacenterId);
  42. try {
  43. //拼接数据中心Id+进程Id
  44. mpid.append(RuntimeUtil.getPid());
  45. } catch (UtilException igonre) {
  46. //ignore
  47. }
  48. /*
  49. * MAC + PID 的 hashcode 获取16个低位 然后对最大的机器节点ID进行取余
  50. */
  51. return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
  52. }

获取Id

  1. /**
  2. * 下一个ID
  3. *
  4. * @return ID
  5. */
  6. public synchronized long nextId() {
  7. long timestamp = genTime();
  8. if (timestamp < this.lastTimestamp) {
  9. if(this.lastTimestamp - timestamp < timeOffset){
  10. // 容忍指定的回拨,避免NTP校时造成的异常
  11. timestamp = lastTimestamp;
  12. } else{
  13. // 如果服务器时间有问题(时钟后退) 报错。
  14. throw new IllegalStateException(StrUtil.format("Clock moved backwards. Refusing to generate id for {}ms", lastTimestamp - timestamp));
  15. }
  16. }
  17. //同一个毫秒时间內,
  18. if (timestamp == this.lastTimestamp) {
  19. //同一个毫秒时间內,说明在这个时间已经获取过一次sequence=0,
  20. final long sequence = (this.sequence + 1) & SEQUENCE_MASK;
  21. //再获取到sequence=0说明出现问题,需要进行等待下一个时间
  22. if (sequence == 0) {
  23. timestamp = tilNextMillis(lastTimestamp);
  24. }
  25. this.sequence = sequence;
  26. } else {
  27. sequence = 0L;
  28. }
  29. lastTimestamp = timestamp;
  30. return ((timestamp - twepoch) << TIMESTAMP_LEFT_SHIFT)
  31. | (dataCenterId << DATA_CENTER_ID_SHIFT)
  32. | (workerId << WORKER_ID_SHIFT)
  33. | sequence;
  34. }
  35. /**
  36. * 循环等待下一个时间
  37. *
  38. * @param lastTimestamp 上次记录的时间
  39. * @return 下一个时间
  40. */
  41. private long tilNextMillis(long lastTimestamp) {
  42. long timestamp = genTime();
  43. // 循环直到操作系统时间戳变化
  44. while (timestamp == lastTimestamp) {
  45. timestamp = genTime();
  46. }
  47. if (timestamp < lastTimestamp) {
  48. // 如果发现新的时间戳比上次记录的时间戳数值小,说明操作系统时间发生了倒退,报错
  49. throw new IllegalStateException(
  50. StrUtil.format("Clock moved backwards. Refusing to generate id for {}ms", lastTimestamp - timestamp));
  51. }
  52. return timestamp;
  53. }

7. java泛型记录

1. 测试代码

  1. public class Main {
  2. public static void main(String[] args) {
  3. // TODO: 普通类继承抽象类 1=10
  4. //带body实现和泛型指定
  5. Type list1 = new ArrayList<String>() {
  6. }.getClass().getGenericSuperclass();
  7. //带泛型不带body
  8. Type list2 = new ArrayList<String>().getClass().getGenericSuperclass();
  9. //带body不带泛型,编译报错 Cannot use "<>"with anonymous inner classes
  10. //Type list3 = new ArrayList<>() {
  11. //}.getClass().getGenericSuperclass();
  12. //什么都不带
  13. Type list4 = new ArrayList<>().getClass().getGenericSuperclass();
  14. // TODO: 接口 2=3
  15. //带body实现和泛型指定
  16. Type a1 = new Aoo<Double>() {
  17. }.getClass().getGenericSuperclass();
  18. //带泛型不带body 编译报错 'Aoo' is abstract; cannot be instantiated
  19. //Type a2 = new Aoo<Double>().getClass().getGenericSuperclass();
  20. //带body不带泛型 编译报错 Cannot use "<>"with anonymous inner classes
  21. //Type a3 = new Aoo<>() {
  22. //}.getClass().getGenericSuperclass();
  23. // TODO: 接口继承接口 3=2
  24. //带body实现和泛型指定
  25. Type c1 = new Coo<String>() {
  26. }.getClass().getGenericSuperclass();
  27. //带泛型不带body 编译报错 'Coo' is abstract; cannot be instantiated
  28. //Type c2 = new Coo<Double>().getClass().getGenericSuperclass();
  29. //带body不带泛型 编译报错 Cannot use "<>"with anonymous inner classes
  30. //Type c3 = new Coo<>() {
  31. //}.getClass().getGenericSuperclass();
  32. // TODO: 普通类实现接口 4=9
  33. //带body实现和泛型指定
  34. Type b1 = new Boo<Double>() {
  35. }.getClass().getGenericSuperclass();
  36. //带泛型不带body
  37. Type b2 = new Boo<String>().getClass().getGenericSuperclass();
  38. //带body不带泛型,编译报错 Cannot use "<>"with anonymous inner classes
  39. //Type b3 = new Boo<>(){}.getClass().getGenericSuperclass();
  40. //什么都不带
  41. Type b4 = new Boo<>().getClass().getGenericSuperclass();
  42. // TODO: 抽象类 5=6=7=8
  43. //带body实现和泛型指定
  44. Type foo1 = new Foo<String>() {
  45. }.getClass().getGenericSuperclass();
  46. //带泛型不带body 编译报错 'Foo' is abstract; cannot be instantiated
  47. //Type foo2=new Foo<String>().getClass().getGenericSuperclass();
  48. //带body不带泛型 编译报错 Cannot use "<>"with anonymous inner classes
  49. //Type foo3=new Foo<>(){}.getClass().getGenericSuperclass();
  50. //TODO: 抽象类继承普通类 6=5=7=8
  51. //带body实现和泛型指定
  52. Type t1 = new Too<String>() {
  53. }.getClass().getGenericSuperclass();
  54. //带泛型不带body 'Too' is abstract; cannot be instantiated
  55. //Type t2 = new Too<String>().getClass().getGenericSuperclass();
  56. //带body不带泛型,编译报错 Cannot use "<>"with anonymous inner classes
  57. //Type t3 = new Too<>() {
  58. //}.getClass().getGenericSuperclass();
  59. // TODO: 抽象类继承抽象类 7=5=6=8
  60. //带body实现和泛型指定
  61. Type rpc1 = new QueueRpcSupport<String>() {
  62. }.getClass().getGenericSuperclass();
  63. //带泛型不带body 编译报错 'QueueRpcSupport' is abstract; cannot be instantiated
  64. //Type rpc2 = new QueueRpcSupport<String>().getClass().getGenericSuperclass();
  65. //带body不带泛型 编译报错 Cannot use "<>"with anonymous inner classes
  66. //Type rpc3 = new QueueRpcSupport<>() {
  67. //}.getClass().getGenericSuperclass();
  68. // TODO: 抽象类实现接口 8=5=6=7
  69. //带body实现和泛型指定
  70. Type d1 = new Doo<Double>() {
  71. }.getClass().getGenericSuperclass();
  72. //带泛型不带body 'Doo' is abstract; cannot be instantiated
  73. //Type d2 = new Doo<String>().getClass().getGenericSuperclass();
  74. //带body不带泛型,编译报错 Cannot use "<>"with anonymous inner classes
  75. //Type d3 = new Doo<>(){}.getClass().getGenericSuperclass();
  76. // TODO: 普通类 9=4
  77. //带body实现和泛型指定
  78. Type z1 = new Zoo<String>() {
  79. }.getClass().getGenericSuperclass();
  80. //带泛型不带body
  81. Type z2 = new Zoo<String>().getClass().getGenericSuperclass();
  82. //带body不带泛型,编译报错 Cannot use "<>"with anonymous inner classes
  83. //Type z3 = new Zoo<>() {
  84. //}.getClass().getGenericSuperclass();
  85. //什么都不带
  86. Type z4 = new Zoo<>().getClass().getGenericSuperclass();
  87. // TODO: 2022/3/18 普通类继承普通类 10=1
  88. //带body实现和泛型指定
  89. Type x1 = new Xoo<String>() {
  90. }.getClass().getGenericSuperclass();
  91. //什么都不带
  92. Type x2 = new Xoo<>().getClass().getGenericSuperclass();
  93. //带body不带泛型,编译报错 Cannot use "<>"with anonymous inner classes
  94. //Type x3 = new Xoo<>() {
  95. //}.getClass().getGenericSuperclass();
  96. //带泛型不带body
  97. Type x4 = new Xoo<String>().getClass().getGenericSuperclass();
  98. System.out.println("test");
  99. }
  100. }
  101. //接口
  102. interface Aoo<E> {
  103. }
  104. //接口继承接口
  105. interface Coo<E> extends Aoo<E> {
  106. }
  107. //抽象类
  108. abstract class Foo<T> {
  109. }
  110. //抽象类实现接口
  111. abstract class Doo<E> implements Coo<E> {
  112. }
  113. //抽象类继承抽象类
  114. abstract class QueueRpcSupport<T> extends Foo<T> {
  115. }
  116. //抽象类继承普通类
  117. abstract class Too<E> extends Boo<E> {
  118. }
  119. //普通类
  120. class Zoo<E> {
  121. }
  122. //普通类实现接口
  123. class Boo<E> implements Aoo<E> {
  124. }
  125. //普通类继承普通类
  126. class Xoo<E> extends Zoo<E> {
  127. }

2. 结果

image.png

3. 结论

  1. 接口/普通类/抽象类的组合 | | 接口 | 抽象类 | 普通类 | | —- | —- | —- | —- | | 接口 | 接口继承接口 | / | / | | 抽象类 | 抽象类实现接口 | 抽象类继承抽象类 | 抽象类继承普通类 | | 普通类 | 普通类实现接口 | 普通类继承抽象类 | 普通类继承普通类 |

  2. 结果分析 | 分类 | 描述 | obj.getClass().getGenericSuperclass()类型 | obj.getClass().getGenericSuperclass()值 | | —- | —- | —- | —- | | 普通类=普通类实现接口 | 带body实现和泛型指定 | ParameterizedTypeImpl | class 具体的类名<具体的泛型> | | | 什么都不带/带泛型不带body | Class | class java.lang.Object | | 普通类继承抽象类
    =普通类继承普通类 | 带body实现和泛型指定 | ParameterizedTypeImpl | class 具体的类名<具体的泛型> | | | 什么都不带/带泛型不带body | ParameterizedTypeImpl | class 具体的类名<泛型定义的名称> | | 接口=接口继承接口 | 必须带body实现和泛型指定 | Class | class java.lang.Object | | 抽象类=抽象类继承抽象类
    =抽象类实现接口
    =抽象类继承普通类 | 必须带body实现和泛型指定 | ParameterizedTypeImpl | class 具体的类名<具体的泛型> | | 其他结论 | | | | | 带body不带泛型,永远不能通过编译,报错 Cannot use “<>”with anonymous inner classes | | | | | 普通类可以出现什么都不带/带泛型不带body,但是接口和抽象类必须带body和泛型指定 | | | |

8. 线程池学习笔记

1. 构造函数

  1. /**
  2. * Creates a new {@code ThreadPoolExecutor} with the given initial
  3. * parameters.
  4. *
  5. * @param corePoolSize the number of threads to keep in the pool, even
  6. * if they are idle, unless {@code allowCoreThreadTimeOut} is set
  7. * @param maximumPoolSize the maximum number of threads to allow in the
  8. * pool
  9. * @param keepAliveTime when the number of threads is greater than
  10. * the core, this is the maximum time that excess idle threads
  11. * will wait for new tasks before terminating.
  12. * @param unit the time unit for the {@code keepAliveTime} argument
  13. * @param workQueue the queue to use for holding tasks before they are
  14. * executed. This queue will hold only the {@code Runnable}
  15. * tasks submitted by the {@code execute} method.
  16. * @param threadFactory the factory to use when the executor
  17. * creates a new thread
  18. * @param handler the handler to use when execution is blocked
  19. * because the thread bounds and queue capacities are reached
  20. * @throws IllegalArgumentException if one of the following holds:<br>
  21. * {@code corePoolSize < 0}<br>
  22. * {@code keepAliveTime < 0}<br>
  23. * {@code maximumPoolSize <= 0}<br>
  24. * {@code maximumPoolSize < corePoolSize}
  25. * @throws NullPointerException if {@code workQueue}
  26. * or {@code threadFactory} or {@code handler} is null
  27. */
  28. public ThreadPoolExecutor(int corePoolSize,
  29. int maximumPoolSize,
  30. long keepAliveTime,
  31. TimeUnit unit,
  32. BlockingQueue<Runnable> workQueue,
  33. ThreadFactory threadFactory,
  34. RejectedExecutionHandler handler) {
  35. if (corePoolSize < 0 ||
  36. maximumPoolSize <= 0 ||
  37. maximumPoolSize < corePoolSize ||
  38. keepAliveTime < 0)
  39. throw new IllegalArgumentException();
  40. if (workQueue == null || threadFactory == null || handler == null)
  41. throw new NullPointerException();
  42. this.acc = System.getSecurityManager() == null ?
  43. null :
  44. AccessController.getContext();
  45. this.corePoolSize = corePoolSize;
  46. this.maximumPoolSize = maximumPoolSize;
  47. this.workQueue = workQueue;
  48. this.keepAliveTime = unit.toNanos(keepAliveTime);
  49. this.threadFactory = threadFactory;
  50. this.handler = handler;
  51. }

2. 构造参数解析

  1. corePoolSize:核心线程数
    1. 核心线程会一直存活,即使没有任务需要执行。
    2. 当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理。
    3. 设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭。
    4. 可以通过 prestartCoreThread() 或 prestartAllCoreThreads() 方法来提前启动线程池中的基本线程。
  2. maximumPoolSize:最大线程数
    1. 线程池所允许的最大线程个数
    2. maxPoolSize>当前线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务。
    3. 当线程数=maxPoolSize,且任务队列已满时,线程池会根据handle策略处理,默认是AbortPolicy 丢弃任务,抛运行时异常。
  3. keepAliveTime:空闲线程存活时间
    1. 当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize。
    2. 如果allowCoreThreadTimeout=true,则会直到线程数量=0。
  4. unit:保持空闲时间的时间单位
  5. workQueue:任务队列

存放待执行任务的队列:当提交的任务数超过核心线程数大小后,再提交的任务就存放在工作队列,任务调度时再从队列中取出任务。它仅仅用来存放被execute()方法提交的Runnable任务。工作队列实现了BlockingQueue接口。
JDK默认的工作队列有五种:

  1. ArrayBlockingQueue 基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。
  2. LinkedBlockingQueue 基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而不会去创建新线程直到maxPoolSize,因此使用该工作队列时,参数maxPoolSize其实是不起作用的。
  3. SynchronousQueue 一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。
  4. PriorityBlockingQueue 具有优先级的无界阻塞队列,优先级通过参数Comparator实现。
  5. DelayQueue 延时队列:无界,元素有过期时间,过期的元素才能被取出。
    1. threadFactory:线程工厂
    2. handler:拒绝策略

当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理,jdk中提供了4中拒绝策略:

  1. CallerRunsPolicy

该策略下,在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务。

  1. public static class CallerRunsPolicy implements RejectedExecutionHandler {
  2. /**
  3. * Creates a {@code CallerRunsPolicy}.
  4. */
  5. public CallerRunsPolicy() { }
  6. /**
  7. * Executes task r in the caller's thread, unless the executor
  8. * has been shut down, in which case the task is discarded.
  9. *
  10. * @param r the runnable task requested to be executed
  11. * @param e the executor attempting to execute this task
  12. */
  13. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
  14. if (!e.isShutdown()) {
  15. r.run();
  16. }
  17. }
  18. }
  1. AbortPolicy

该策略下,直接丢弃任务,并抛出RejectedExecutionException异常

  1. public static class AbortPolicy implements RejectedExecutionHandler {
  2. /**
  3. * Creates an {@code AbortPolicy}.
  4. */
  5. public AbortPolicy() { }
  6. /**
  7. * Always throws RejectedExecutionException.
  8. *
  9. * @param r the runnable task requested to be executed
  10. * @param e the executor attempting to execute this task
  11. * @throws RejectedExecutionException always
  12. */
  13. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
  14. throw new RejectedExecutionException("Task " + r.toString() +
  15. " rejected from " +
  16. e.toString());
  17. }
  1. DiscardPolicy

该策略下,直接丢弃任务,什么都不做。

  1. /**
  2. * A handler for rejected tasks that silently discards the
  3. * rejected task.
  4. */
  5. public static class DiscardPolicy implements RejectedExecutionHandler {
  6. /**
  7. * Creates a {@code DiscardPolicy}.
  8. */
  9. public DiscardPolicy() { }
  10. /**
  11. * Does nothing, which has the effect of discarding task r.
  12. *
  13. * @param r the runnable task requested to be executed
  14. * @param e the executor attempting to execute this task
  15. */
  16. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
  17. }
  18. }
  1. DiscardOldestPolicy

该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列

  1. public static class DiscardOldestPolicy implements RejectedExecutionHandler {
  2. /**
  3. * Creates a {@code DiscardOldestPolicy} for the given executor.
  4. */
  5. public DiscardOldestPolicy() { }
  6. /**
  7. * Obtains and ignores the next task that the executor
  8. * would otherwise execute, if one is immediately available,
  9. * and then retries execution of task r, unless the executor
  10. * is shut down, in which case task r is instead discarded.
  11. *
  12. * @param r the runnable task requested to be executed
  13. * @param e the executor attempting to execute this task
  14. */
  15. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
  16. if (!e.isShutdown()) {
  17. e.getQueue().poll();
  18. e.execute(r);
  19. }
  20. }

3. ThreadPoolExecutor执行过程

  1. 当线程数小于核心线程数时,创建线程。
  2. 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
  3. 当线程数大于等于核心线程数,且任务队列已满。
    1. 若线程数小于最大线程数,创建线程。
    2. 若线程数等于最大线程数,抛出异常,拒绝任务。

image.png
image.png

4. Executors提供的几种线程池

1. newCachedThreadPool

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newCachedThreadPool:用来创建一个可以无限扩大的线程池,适用于负载较轻的场景,执行短期异步任务。(可以使得任务快速得到执行,因为任务时间执行短,可以很快结束,也不会造成cpu过度切换)

  1. public static ExecutorService newCachedThreadPool() {
  2. return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
  3. 60L, TimeUnit.SECONDS,
  4. new SynchronousQueue<Runnable>());
  5. }
  6. public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
  7. return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
  8. 60L, TimeUnit.SECONDS,
  9. new SynchronousQueue<Runnable>(),
  10. threadFactory);
  11. }
  1. corePoolSize 核心线程数设置为0,即所有线程在60s超时后都可以被回收进行利用
  2. maximumPoolSize 最大线程数设置为Integer.MAX_VALUE,可以创建非常多的线程,即任务可以得到快速响应
  3. SynchronousQueue 使用同步的任务队列

    2. newFixedThreadPool

    newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
    newFixedThreadPool:创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变化,适用于负载较重的场景,对当前线程数量进行限制。(保证线程数可控,不会造成线程过多,导致系统负载更为严重)

    1. public static ExecutorService newFixedThreadPool(int nThreads) {
    2. return new ThreadPoolExecutor(nThreads, nThreads,
    3. 0L, TimeUnit.MILLISECONDS,
    4. new LinkedBlockingQueue<Runnable>());
    5. }
    6. public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    7. return new ThreadPoolExecutor(nThreads, nThreads,
    8. 0L, TimeUnit.MILLISECONDS,
    9. new LinkedBlockingQueue<Runnable>(),
    10. threadFactory);
    11. }
  4. corePoolSize 核心线程数和maximumPoolSize 最大线程数相等,即线程大小是固定的

  5. LinkedBlockingQueue:使用链表型阻塞队列
  6. 超时时间为0,理解为不需要超时时间,因为最大线程数=核心线程数,即当前在运行的所有线程都是核心线程,不会出现超时回收。

    3. newScheduledThreadPool

    newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
    newScheduledThreadPool:适用于执行延时或者周期性任务。 ```java public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    1. return new ScheduledThreadPoolExecutor(corePoolSize);
    } public ScheduledThreadPoolExecutor(int corePoolSize) {
    1. super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
    2. new DelayedWorkQueue());
    }

// public static ScheduledExecutorService newScheduledThreadPool( int corePoolSize, ThreadFactory threadFactory) { return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); } public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory); }

  1. 1. 指定核心线程数,最大线程数为Integer.MAX_VALUE,超时时间单位设置很短,对时间精度要求较高
  2. 1. DelayedWorkQueue 使用延时队列实现周期性执行
  3. <a name="kOQ0R"></a>
  4. ### 4. newSingleThreadExecutor
  5. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO优先级)执行。
  6. ```java
  7. public static ExecutorService newSingleThreadExecutor() {
  8. return new FinalizableDelegatedExecutorService
  9. (new ThreadPoolExecutor(1, 1,
  10. 0L, TimeUnit.MILLISECONDS,
  11. new LinkedBlockingQueue<Runnable>()));
  12. }
  13. public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
  14. return new FinalizableDelegatedExecutorService
  15. (new ThreadPoolExecutor(1, 1,
  16. 0L, TimeUnit.MILLISECONDS,
  17. new LinkedBlockingQueue<Runnable>(),
  18. threadFactory));
  19. }
  1. 核心线程数和最大线程数都是一个
  2. 使用LinkedBlockingQueue 保证FIFO

    5. newSingleThreadScheduledExecutor

    单线程周期性执行线程池,有点像newSingleThreadExecutor和newScheduledThreadPool的结合
    顺序执行,周期执行
    1. public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
    2. return new DelegatedScheduledExecutorService
    3. (new ScheduledThreadPoolExecutor(1));
    4. }
    5. public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
    6. return new DelegatedScheduledExecutorService
    7. (new ScheduledThreadPoolExecutor(1, threadFactory));
    8. }

    5. 线程池表格比较

    | 方法 | corePoolSize | maximumPoolSize | keepAliveTime | workQueue | | —- | —- | —- | —- | —- | | newCachedThreadPool | 0 | Integer.MAX_VALUE | 60s | SynchronousQueue | | newFixedThreadPool | n | n | 0 | LinkedBlockingQueue | | newScheduledThreadPool | n | Integer.MAX_VALUE | 0 | DelayedWorkQueue | | newSingleThreadExecutor | 1 | 1 | 0 | LinkedBlockingQueue | | newSingleThreadScheduledExecutor | 1 | Integer.MAX_VALUE | 0 | DelayedWorkQueue |

6. 线程池源码学习记录

  1. public class ThreadPoolExecutor extends AbstractExecutorService {
  2. workerCount, indicating the effective number of threads
  3. /**
  4. * The main pool control state, ctl, is an atomic integer packing
  5. * two conceptual fields
  6. * workerCount, indicating the effective number of threads
  7. * runState, indicating whether running, shutting down etc
  8. */
  9. private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
  10. //计数的一个基准,用的是Integer.SIZE-3,至于为什么是-3,而不是其他数字,下面会重点分析
  11. private static final int COUNT_BITS = Integer.SIZE - 3;
  12. //CAPACITY,用来从ctl中获取字段
  13. private static final int CAPACITY = (1 << COUNT_BITS) - 1;
  14. // runState is stored in the high-order bits 注释提示:runState被存储在高位中
  15. private static final int RUNNING = -1 << COUNT_BITS;
  16. private static final int SHUTDOWN = 0 << COUNT_BITS;
  17. private static final int STOP = 1 << COUNT_BITS;
  18. private static final int TIDYING = 2 << COUNT_BITS;
  19. private static final int TERMINATED = 3 << COUNT_BITS;
  20. // Packing and unpacking ctl 提示:下面的方法用于将数据存储到ctl中和从ctl中获取字段 入参c都是ctl变量的值
  21. private static int runStateOf(int c) { return c & ~CAPACITY; }
  22. private static int workerCountOf(int c) { return c & CAPACITY; }
  23. //ctl数据存储格式:rs 00xxx00 wc 表名rs存储在高位,wc存储在低位,我们要从ctl获取某一个字段,就要想办法舍弃另一个字段
  24. private static int ctlOf(int rs, int wc) { return rs | wc; }

各个变量的二进制表示 (橙色标识Integer.SIZE - 3=29位)

变量名 二进制
CAPACITY 0001 1111 1111 1111 1111 1111 1111 1111
RUNNING 1010 0000 0000 0000 0000 0000 0000 0000
SHUTDOWN 0000 0000 0000 0000 0000 0000 0000 0000
STOP 0010 0000 0000 0000 0000 0000 0000 0000
TIDYING 0100 0000 0000 0000 0000 0000 0000 0000
TERMINATED 0110 0000 0000 0000 0000 0000 0000 0000

这里解释为什么COUNT_BITS=Integer.SIZE - 3,是3而不是其他数字?
ctl 里面存储的字段格式为:rs|ws 即rs运行状态在高位,ws工作线程的数量在低位
因为线程池的状态总共有5种,ctl 中将状态存储在高位,1位bit最多可存储2种,2位bit最多可存储4种,3位bit最多可存储7种,故这里的COUNT_BITS使用了Integer.SIZE - 3就足够存储状态了。

& 按位与,与0计算被舍弃,与1计算保留原值
workerCountOf方法解析
c & CAPACITY
rs 00…00 ws & 0001 1111 1111 1111 1111 1111 1111 1111
CAPACITY前三位为0后面都为1,故前三位rs被舍弃,其他位ws全部保留
最后返回ws工作线程的数量
runStateOf方法解析
c & ~CAPACITY
rs 00…00 ws & 1110 0000 0000 0000 0000 0000 0000 0000
~CAPACITY只有前面三位为1后面都为0,故前面三位rs的值被保留,其他位ws全部舍弃。
最后返回rs工线程池的状态。
妙啊~

9.String.format用法记录

  1. @Test
  2. public void test2() {
  3. //字符串右边补充占位符
  4. System.out.println(String.format("%-15s", "sadddddds").replace(' ', '_'));
  5. //字符串左边补充占位符
  6. System.out.println(String.format("%15s", "sadddddds").replace(' ', '_'));
  7. //数字右边补充占位符
  8. System.out.println(String.format("%-10d", 122323).replace(' ', '0'));
  9. //数字左边补充占位符方式一
  10. System.out.println(String.format("%10d", 122323).replace(' ', '0'));
  11. //数字左边补充占位符方式二
  12. System.out.println(String.format("%010d", 122323));
  13. }

结果:
image.png

10. java命令行命令记录

  1. 命令行运行jar包命令 java 参数 -jar jar包名 yml配置(使用—配置,比如:—spring.profiles.active=pre)
    1. 指定文件编码:-Dfile.encoding=utf-8
    2. 指定profile文件 —spring.profiles.active=pre
  2. 其他命令
    1. 编译 javac xxx.java -encoding UTF-8 指定文件编码格式
    2. 反汇编 javap -verbose xxx.class

      11. spring 事务传播特性

      spring支持7种事务传播行为,分别为:

propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作。

12 Cron表达式记录

格式

(cron = “ “)
{秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)}
例 “0 0 12 ? * WED” 在每星期三下午12:00 执行(年份通常 省略)

每个字段的允许值

字段 允许值 允许的特殊字符
秒 0-59 , - /
分 0-59 , -
/
小时 0-23 , - /
日期 1-31 , -
? / L W C
月份 1-12 或者 JAN-DEC , - /
星期 1-7 或者 SUN-SAT , -
? / L C #
年(可选) 留空, 1970-2099 , - * /

允许值的意思

Seconds (秒) :可以用数字0-59 表示
Minutes(分) :可以用数字0-59 表示
Hours(时) :可以用数字0-23表示
Day-of-Month(天) :可以用数字1-31 中的任一一个值,但要注意一些特别的月份
Month(月) :可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
Day-of-Week(每周):可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示

每个符号的意义

    • 表示所有值;
  1. ? 表示未说明的值,即不关心它为何值;
    • 表示一个指定的范围;
  2. , 表示附加一个可能值;
  3. / 符号前表示开始时间,符号后表示每次递增的值;
  4. L(“last”) (“last”) “L” 用在day-of-month字段意思是 “这个月最后一天”;用在 day-of-week字段, 它简单意思是 “7” or “SAT”。 如果在day-of-week字段里和数字联合使用,它的意思就是 “这个月的最后一个星期几” – 例如: “6L” means “这个月的最后一个星期五”. 当我们用“L”时,不指明一个列表值或者范围是很重要的,不然的话,我们会得到一些意想不到的结果。
  5. W(“weekday”) 只能用在day-of-month字段。用来描叙最接近指定天的工作日(周一到周五)。例如:在day-of-month字段用“15W”指“最接近这个 月第15天的工作日”,即如果这个月第15天是周六,那么触发器将会在这个月第14天即周五触发;如果这个月第15天是周日,那么触发器将会在这个月第 16天即周一触发;如果这个月第15天是周二,那么就在触发器这天触发。注意一点:这个用法只会在当前月计算值,不会越过当前月。“W”字符仅能在 day-of-month指明一天,不能是一个范围或列表。也可以用“LW”来指定这个月的最后一个工作日。
  6. 只能用在day-of-week字段。用来指定这个月的第几个周几。例:在day-of-week字段用”6#3”指这个月第3个周五(6指周五,3指第3个)。如果指定的日期不存在,触发器就不会触发。

  7. C 指和calendar联系后计算过的值。例:在day-of-month 字段用“5C”指在这个月第5天或之后包括calendar的第一天;在day-of-week字段用“1C”指在这周日或之后包括calendar的第一天。

    一些cron表达式案例

    /5 ? 每隔5秒执行一次
    0
    /1 ? 每隔1分钟执行一次
    0 0 5-15
    ? 每天5-15点整点触发
    0 0/3
    ? 每三分钟触发一次
    0 0-5 14 ? 在每天下午2点到下午2:05期间的每1分钟触发
    0 0/5 14 ? 在每天下午2点到下午2:55期间的每5分钟触发
    0 0/5 14,18 ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
    0 0/30 9-17 ? 朝九晚五工作时间内每半小时
    0 0 10,14,16 ? 每天上午10点,下午2点,4点

    0 0 12 ? WED 表示每个星期三中午12点
    0 0 17 ?
    TUES,THUR,SAT 每周二、四、六下午五点
    0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发
    0 15 10 ? MON-FRI 周一至周五的上午10:15触发
    0 0 23 L
    ? 每月最后一天23点执行一次
    0 15 10 L ? 每月最后一日的上午10:15触发
    0 15 10 ?
    6L 每月的最后一个星期五上午10:15触发
    0 15 10 ? 2005 2005年的每天上午10:15触发
    0 15 10 ? 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发
    0 15 10 ?
    6#3 每月的第三个星期五上午10:15触发

“30 ?” 每半分钟触发任务
“30 10 ?” 每小时的10分30秒触发任务
“30 10 1
?” 每天1点10分30秒触发任务
“30 10 1 20
?” 每月20号1点10分30秒触发任务
“30 10 1 20 10 ? “ 每年10月20号1点10分30秒触发任务
“30 10 1 20 10 ? 2011” 2011年10月20号1点10分30秒触发任务
“30 10 1 ? 10
2011” 2011年10月每天1点10分30秒触发任务
“30 10 1 ? 10 SUN 2011” 2011年10月每周日1点10分30秒触发任务
“15,30,45 ?” 每15秒,30秒,45秒时触发任务
“15-45 ?” 15到45秒内,每秒都触发任务
“15/5 ?” 每分钟的每15秒开始触发,每隔5秒触发一次
“15-30/5 ?” 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次
“0 0/3 ?” 每小时的第0分0秒开始,每三分钟触发一次
“0 15 10 ?
MON-FRI” 星期一到星期五的10点15分0秒触发任务
“0 15 10 L ?” 每个月最后一天的10点15分0秒触发任务
“0 15 10 LW
?” 每个月最后一个工作日的10点15分0秒触发任务
“0 15 10 ? 5L” 每个月最后一个星期四的10点15分0秒触发任务
“0 15 10 ?
5#3” 每个月第三周的星期四的10点15分0秒触发任务

在线cron表达式生成器

bejson在线cron表达式生成器

13. LocalDateTime和时间戳互转

Java8的时间转为时间戳的大概的思路就是LocalDateTime先转为Instant,设置时区,然后转timestamp。

  1. Instant instant = Instant.ofEpochMilli(timestamp);
  2. LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
  1. long timestamp = ldt.toInstant(ZoneOffset.of("+8")).toEpochMilli();
  2. //或者
  3. ZoneId zone = ZoneId.systemDefault();
  4. long timestamp = ldt.atZone(zone).toInstant().toEpochMilli();


14. logback配置详情

参考链接

15. 使用增强for进行迭代不允许修改的原理记录

以ArrayList为例,它的迭代使用的next方法会调用以下方法

  1. final void checkForComodification() {
  2. if (modCount != expectedModCount)
  3. throw new ConcurrentModificationException();
  4. }

modCount是AbstractList(ArrayList的父类)中用来记录集合被修改次数的一个变量,ArrayList中的修改(特指增加和删除)集合元素的方法都会对这个变量进行修改。
expectedModCount是集合在迭代开始的时候自动生成的变量,它默认是等于modCount的值。当我们在迭代中增加或删除了集合的元素会modCount的值,而expectedModCount未修改,在for的下一次循环中就会抛出异常ConcurrentModificationException。
这里有一个特殊的地方是,如果你在倒数第二次迭代的时候删除集合的元素是不会抛出异常的。
测试代码如下

  1. public class 迭代修改元素测试 {
  2. public static void main(String[] args) {
  3. List<Integer> list = IntStream.rangeClosed(0, 5).boxed().collect(Collectors.toList());
  4. int i = 0;
  5. for (Integer integer : list) {
  6. if (i == list.size() - 2) {
  7. list.remove(4);
  8. }
  9. i++;
  10. System.out.println(integer);
  11. }
  12. }
  13. }

image.png
这是因为在倒数第二次遍历时候调用删除方法,增强for默认调用的hasNext()方法会去判断当前的遍历的指针是否等于现在集合中的元素,因为集合的元素被删除了,容量变小了,所以此时的判断是相等的,不会进行下一次遍历,故这样就避开了next方法里面可能会抛出异常的判断。

  1. public boolean hasNext() {
  2. return cursor != size;
  3. }

集合遍历的时候想要删除集合元素可以使用Iterator提供的remove()接口进行删除,因为在remove方法中回去重新将modCount的值赋给expectedModCount,这样就不会发生异常。
或者使用集合提供的removeIf条件删除方法传入条件进行删除

  1. public void remove() {
  2. if (lastRet < 0)
  3. throw new IllegalStateException();
  4. checkForComodification();
  5. try {
  6. ArrayList.this.remove(lastRet);
  7. cursor = lastRet;
  8. lastRet = -1;
  9. expectedModCount = modCount;
  10. } catch (IndexOutOfBoundsException ex) {
  11. throw new ConcurrentModificationException();
  12. }
  13. }

16. 位运算使用记录

20190115164357116[1].png
求两个数a,b的平均值
mid=(a+b)>>>1

17. jconsole远程监控

  1. -Dcom.sun.management.jmxremote=true
  2. #jconsole连接使用的端口
  3. -Dcom.sun.management.jmxremote.port=8888
  4. -Dcom.sun.management.jmxremote.authenticate=false
  5. -Dcom.sun.management.jmxremote.ssl=false
  6. #192.168.1.207为当前服务器的ip
  7. -Djava.rmi.server.hostname=192.168.1.207