jdk相关知识

112 阅读2分钟

1、Random

Math.random():生成【0.0,1.0]之间的double类型的随机数。 Random:可以生成各种类型的随机数。nextInt表示【0,1],nextLong、nextBoolean等类型。

public static void main(String[] args) {

    Random random = new Random();
    random.setSeed(1);

    Random random1 = new Random();
    random1.setSeed(2);

    for (int i = 0; i < 20; i++) {
        int j = random.nextInt(10);
        System.out.print(j);
        System.out.print(" ");
    }
    System.out.println();
    for (int i = 0; i < 20; i++) {
        int j = random1.nextInt(10);
        System.out.print(j);
        System.out.print(" ");
    }

}

种子seed表示具有同一种子的Random,生成的随机数一样。如上述所示,其结果输出是一样的。

2、定时执行任务

  1. scheduleAtFixedRate :是以上一个任务开始的时间计时,period时间过去后,检测上一个任务是否执行完毕,如果上一个任务执行完毕,则当前任务立即执行,如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行。
  2. scheduleWithFixedDelay,是以上一个任务结束时开始计时,period时间过去后,立即执行。
  3. 即使定时执行器存在多个核心线程数,多线程执行过程遵循步骤1、2规范。
  4. 通过ScheduledExecutorService执行的周期任务,如果任务执行过程中抛出了异常,那么过ScheduledExecutorService就会停止执行任务,且也不会再周期地执行该任务了。所以你如果想保住任务都一直被周期执行,那么catch一切可能的异常。

2.1、ThreadPoolTaskScheduler

  1. ThreadPoolTaskScheduler默认是单线程的线程定时器。也可以设置核心线程数。
  2. 该类继承至抽象类ExecutorConfigurationSupport。
  3. 抽象类ExecutorConfigurationSupport实现了InitializingBean接口。
  4. 抽象类ExecutorConfigurationSupport其子类在完成IOC容器的实例化之后,在initializeBean方法中触发回调InitializingBean接口的默认方法afterPropertiesSet方法。
  5. 步骤4中完成ThreadPoolTaskScheduler类涉及的ThreadPoolExecutor执行器【队列、核心线程数、最大线程数、拒绝策略、线程活跃时间、时间单位、线程工厂类等】,真正用于启动线程执行任务。

3、Comparator#compare

结论之原序 & 反序:

  • 如果compare方法永远返回负数【negative】,则对原集合元素反序【倒序】处理。
  • 如果compare方法永远返回正数或者0【positive、zero】,则保持原集合元素的顺序【原序】。

结论之升序 & 降序:

list.sort(new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        int rtn = o1 - o2;//原集合升序排序
        //int rtn = o2 - o1;//原集合降序排序
        //rtn = 0或者正数,集合最终还是原序,也就是没做任何排序
        //rtn = -1 或者负数,集合做倒序处理
        return rtn;
    }
});

思考问题:为啥o1-o2表示原集合升序排序?o2 - o1 表示原集合降序排序?

TimSort#sort方法:

if (nRemaining < MIN_MERGE) {
    int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
    binarySort(a, lo, hi, lo + initRunLen, c);
    return;
}

如果自定义compare方法一直返回负数或者0或者正数,则最终initRunLen值为集合之size or length。则不符合binarySort方法执行条件。

private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,
                                                    Comparator<? super T> c) {
    // lo表示数组的起始位置 即:数组下标0
    assert lo < hi;
    int runHi = lo + 1;
    // hi表示数组长度
    if (runHi == hi)
        return 1;

    // c.compare()方法就是我们自定义的
    // 如果按照指定规则数组的前一段是“降序”的,需要反转为正序
    if (c.compare(a[runHi++], a[lo]) < 0) { // Descending  调用自定义
        // 从这里可以看到传入到compare(o1, o2)方法的参数,在原数组中 o2 在 o1 前面
        while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0) // 调用自定义
            runHi++;
        reverseRange(a, lo, runHi);
    } else {                              // Ascending
        while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
            runHi++;
    }
    // 表示 runHi -lo个元素已经按规则“正序”排好序了
    return runHi - lo;
}

countRunAndMakeAscending核心方法功能:确认原集合中有序子集合[0,initRunLen),initRunLen>=2。

o1 -o2,即当前元素与之前某个元素的差:如果原集合前个元素升序,则其相邻元素之间差大于0,则[0,initRunLen)之间的元素维持其顺序,也即升序排列;如果原集合前个元素降序,则其相邻元素之间差小于0,则[0,initRunLen)之间的元素会进行倒序处理,最终结果还为升序。

o2 -o1,即当前元素与之后某个元素的差:如果原集合前个元素升序,则其相邻元素之间差小于0,[0,initRunLen)之间的元素会进行倒序处理,最终结果[0,initRunLen)之间的元素还为降序;如果原集合前个元素降序,则其相邻元素之间差大于0,[0,initRunLen)之间的元素维持其顺序,也即降序排列。

//lo表示数组起始下标 hi临界下标
private static void reverseRange(Object[] a, int lo, int hi) {
   hi--;
    while (lo < hi) {
        Object t = a[lo];
        a[lo++] = a[hi];
        a[hi--] = t;
    }
}

该方法:反转数组中下标区间为[lo,hi)之间的元素。第一个 & 最后一个交换、第二个&倒数第二个交换、... and so on。 备注:在此之前已经确定了[lo, runHi)之间的元素是存在顺序的。

//hi表示始终为原集合长度   lo始终为0   start表示起始集合下标
private static <T> void binarySort(T[] a, int lo, int hi, int start,
                                   Comparator<? super T> c) {//快排算法
    assert lo <= start && start <= hi;
    if (start == lo)
        start++;
    for ( ; start < hi; start++) {//以下排序是确定index = start的元素在有序子集合[0,start)中的位置
        T pivot = a[start];
        int left = lo;
        int right = start;
        assert left <= right;
        while (left < right) {
        	// 11 3 45 6 34
            int mid = (left + right) >>> 1;
            if (c.compare(pivot, a[mid]) < 0)
                right = mid;
            else
                left = mid + 1;
        }
        assert left == right;
        int n = start - left;  // The number of elements to move
        // Switch is just an optimization for arraycopy in default case
        switch (n) {
            case 2:  a[left + 2] = a[left + 1];
            case 1:  a[left + 1] = a[left];
                     break;
            default: System.arraycopy(a, left, a, left + 1, n);
        }
        a[left] = pivot;
    }
}

前提:在执行该方法之前其[lo,start)区间的元素是有序的。而且已经确定集合元素的顺序方式【降序 or 升序】。 利用快排算法处理元素顺序。