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、定时执行任务
- scheduleAtFixedRate :是以上一个任务开始的时间计时,period时间过去后,检测上一个任务是否执行完毕,如果上一个任务执行完毕,则当前任务立即执行,如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行。
- scheduleWithFixedDelay,是以上一个任务结束时开始计时,period时间过去后,立即执行。
- 即使定时执行器存在多个核心线程数,多线程执行过程遵循步骤1、2规范。
- 通过ScheduledExecutorService执行的周期任务,如果任务执行过程中抛出了异常,那么过ScheduledExecutorService就会停止执行任务,且也不会再周期地执行该任务了。所以你如果想保住任务都一直被周期执行,那么catch一切可能的异常。
2.1、ThreadPoolTaskScheduler
- ThreadPoolTaskScheduler默认是单线程的线程定时器。也可以设置核心线程数。
- 该类继承至抽象类ExecutorConfigurationSupport。
- 抽象类ExecutorConfigurationSupport实现了InitializingBean接口。
- 抽象类ExecutorConfigurationSupport其子类在完成IOC容器的实例化之后,在initializeBean方法中触发回调InitializingBean接口的默认方法afterPropertiesSet方法。
- 步骤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 升序】。
利用快排算法处理元素顺序。