1. ForkJoinPool的理解
分治思想的体现,将一个任务分成(fork())若干子任务交给不同的线程进行执行,结束后把各个子任务的结果汇总归并(join)成最终结果。
工作窃取:如果某个子线程上的任务队列(双
分治思想的体现,将一个任务分成(fork())若干子任务交给不同的线程进行执行,结束后把各个子任务的结果汇总归并(join)成最终结果。
工作窃取:如果某个子线程上的任务队列(双端队列)为空时,会去其他子线程的任务队列进行“窃取”来执行,进而提升整个任务的执行效率,充分利用所有线程的计算能力。
2. CompletableFutrue的理解
继承Thread类或者实现Runnable接口创建的线程都没有返回值,我们无法得知线程的执行结果。因此在Java1.5后加入了Callable接口和Future类来进行补充。
但是当我们在主线程中创建Future线程,然后使用get()方法来获取线程执行后的返回值时,主线程会陷入阻塞,这会浪费时间和性能。
为了解决这个问题,CompletableFuture类诞生了(Java8),它可以帮助我们简化异步编程。在主线程之外创建一个独立的线程,并在上面运行一个非阻塞的任务,运行完成后通知主线程成功或失败。通过这种方式,主线程不用为了任务的完成而阻塞,可以去执行其他任务。
3. 归并排序?多线程版本?
归并排序:
static int[] array;
public static void main(String[] args) {
array = new int[100];
//随机100个数的数组
for (int i = 0; i < 100; i++) {
array[i] = (int) (Math.random() * 1000);
}
System.out.println(Arrays.toString(array));
mergeSort(0, 99);
System.out.println(Arrays.toString(array));
}
public static void mergeSort(int left, int right) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(left, mid);
mergeSort(mid + 1, right);
merge(left, mid, right);
}
}
public static void merge(int left, int mid, int right) {
int[] temp = new int[right - left + 1];
int index = 0;//用于向临时数组加入元素
int index1 = left;//用于第一个数组的遍历
int index2 = mid + 1;//用于第二个数组的遍历
//遍历两个数组,按照从小到大顺序放入临时数组,一共有right-left+1个元素
while (index1 <= mid && index2 <= right) {
if (index1 > mid | index2 > right)//某个要归并的数组已经全部都归并了
break;
if (array[index1] <= array[index2])//带上=可以保证稳定性
temp[index++] = array[index1++];
else
temp[index++] = array[index2++];
}
//剩下的数组中的元素也依次放入临时数组
while (index1 <= mid)
temp[index++] = array[index1++];
while (index2 <= right)
temp[index++] = array[index2++];
//再把临时数组的元素放回原数组
if (right + 1 - left >= 0) System.arraycopy(temp, 0, array, left, right + 1 - left);
}
多线程版本:
import java.util.Arrays;
import java.util.concurrent.ForkJoinPool;
public class MergeSortMultiThread {
static int[] array;
public static void main(String[] args) {
array = new int[100];
//随机100个数的数组
for (int i = 0; i < 100; i++) {
array[i] = (int) (Math.random() * 1000);
}
System.out.println(Arrays.toString(array));
//最外层的线程
Thread t = new MergeSortMultiThread.mergeSortThread(0,99);
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Arrays.toString(array));
}
static class mergeSortThread extends Thread{
int left;
int right;
public mergeSortThread(int left, int right) {
this.left = left;
this.right = right;
}
@Override
public void run() {
if (left < right) {
int mid = (left + right) / 2;
Thread t1 = new mergeSortThread(left,mid);
Thread t2 = new mergeSortThread(mid+1,right);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
merge(left, mid, right);
}
}
public static void merge(int left, int mid, int right) {
int[] temp = new int[right - left + 1];
int index = 0;//用于向临时数组加入元素
int index1 = left;//用于第一个数组的遍历
int index2 = mid + 1;//用于第二个数组的遍历
//遍历两个数组,按照从小到大顺序放入临时数组,一共有right-left+1个元素
while (index1 <= mid && index2 <= right) {
//注意判断越界问题,比如两个index中有一个已经到达边界之后,还有一个数组有剩余元素,那就还需要继续加入临时数组,此时再比较会越界
if (index1 > mid | index2 > right)//某个要归并的数组已经全部都归并了
break;
if (array[index1] <= array[index2])//带上=可以保证稳定性
temp[index++] = array[index1++];
else
temp[index++] = array[index2++];
}
//剩下的数组中的元素也依次放入临时数组
while (index1 <= mid)
temp[index++] = array[index1++];
while (index2 <= right)
temp[index++] = array[index2++];
//再把临时数组的元素放回原数组
if (right + 1 - left >= 0) System.arraycopy(temp, 0, array, left, right + 1 - left);
}
}
}