本文讲述简单的多线程应用:
1、多线程排序,即把数据存放在一维数组中,首先对数据进行分段,接着对每 一段数据采用经典排序算法实现排序,最后把各段数据进行合并排序。请完成程序编写。
2、多线程求数组最大值,即把数据存放在一维数组中,首先对数据进行分段, 接着对每一段数据求得最大值,最后把各段数据最大值进行比较从而得出整个 数组的最大值。请完成程序编写。
3、采用线程实现“生产者-消费者”编程的基础模型。
先试一下我们不用多线程的情况,以快速排序为例
package advance1;/*
* @Author: Gnight
* @Date: 2020/12/17 23:32
* @Description:
单线程的快速排序,太多数据栈会溢出
*/
import java.util.Arrays;
public class JavaDemo {
public static int[] arr;
public static void main(String[] args) {
//随机生成数值
arr = new int[100];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * 1000);
}
new JavaDemo().doSort(0, arr.length - 1);
for (int element : arr) {
System.out.println(element);
}
}
public void doSort(int low, int high) {
if (low < high) {
int index = quickSort(low, high);//实际的排序流程
doSort(low, index - 1);
doSort(index + 1, high);
}
}
public int quickSort(int i, int j) {
int key = arr[i];//基准值
while (i < j) {
//找出第一个右边要交换的
while (i < j && arr[j] >= key) j--;
if (i < j) arr[i] = arr[j];
//找出第一个左边要交换的
while (i < j && arr[i] <= key) i++;
if (i < j) arr[j] = arr[i];
}
// i== j的情况
arr[i] = key;
return i;
}
}
那么如何实现多线程呢?
对数据分段,分别建立线程执行
合并每一段的结果
数据分段:
//根据我们设立的线程数来分段
for (int i = 0; i < threadNum; i++) {
int[] temp = Arrays.copyOfRange(arr, i * arr.length / threadNum,
(i + 1) * arr.length / threadNum);
//theadNum就是线程数
}
快排线程:采用Callable接口,可以有返回值
package advance1;/*
* @Author: Gnight
* @Date: 2020/12/17 19:10
* @Description:
多线程实现快排
*/
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
//快排多线程
public class sortThread implements Callable<int[]> {
private int[] arr;
private int low;
private int high;
private CountDownLatch count;
public sortThread(int[] arr, int low, int high, CountDownLatch count) {
this.arr = arr;
this.low = low;
this.high = high;
this.count = count;
}
public int[] call() throws Exception {
System.out.println("线程 " + Thread.currentThread().getName() + " 开始");
doSort(low, high);
int[] res = new int[high - low + 1];
int index = 0;
for (int i = low; i < high + 1; i++) {
res[index++] = arr[i];
}
try {
return arr;
} finally {
count.countDown();
System.out.println("线程 " + Thread.currentThread().getName() + " 结束");
}
}
public void doSort(int low, int high) {
if (low < high) {
int index = quickSort(low, high);//实际的排序流程
doSort(low, index - 1);
doSort(index + 1, high);
}
}
public int quickSort(int i, int j) {
int key = arr[i];//基准值
while (i < j) {
//找出第一个右边要交换的
while (i < j && arr[j] >= key) j--;
if (i < j) arr[i] = arr[j];
//找出第一个左边要交换的
while (i < j && arr[i] <= key) i++;
if (i < j) arr[j] = arr[i];
}
// i== j的情况
arr[i] = key;
return i;
}
}
创建多线程,使用CountDownLatch
保证前面都完成后再对数据段合并
try {
CountDownLatch count = new CountDownLatch(threadNum);
for (int i = 0; i < threadNum; i++) {
int[] temp = Arrays.copyOfRange(arr, i * arr.length / threadNum, (i + 1) * arr.length / threadNum);
Future<int[]> future = pool.submit(new sortThread(temp, 0,
temp.length - 1, count));
res[i] = future.get();
}
/*
使用CountDownLatch来保证前面线程都排序完,然后对排序完的升序数组合并
*/
count.await();
//这里排序亦可使用多线程
int[] m1 = merge(res[0], res[1]);
int[] m2 = merge(res[2], res[3]);
arr = merge(m1, m2);
} catch (Exception e) {
e.printStackTrace();
}
package advance1;/*
* @Author: Gnight
* @Date: 2020/12/17 12:38
* @Description:
多线程实现排序:合并的时候也可以使用多线程
*/
import java.util.Arrays;
import java.util.concurrent.*;
public class SortDemo {
public static void main(String[] args) {
//线程数
int threadNum = 4;
System.out.println("创建线程数:" + threadNum);
//创建线程池
ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(threadNum);
int[] arr = new int[5000000];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * 1000);
}
// display("排序前:", arr, ""); 太多了暂时不显示
//最后的数组
int[][] res = new int[threadNum][];
//多线程排序
try {
CountDownLatch count = new CountDownLatch(threadNum);
for (int i = 0; i < threadNum; i++) {
int[] temp = Arrays.copyOfRange(arr, i * arr.length / threadNum, (i + 1) * arr.length / threadNum);
Future<int[]> future = pool.submit(new sortThread(temp, 0,
temp.length - 1, count));
res[i] = future.get();
}
count.await();
//将结果归并,可改为多线程
int[] m1 = merge(res[0], res[1]);
int[] m2 = merge(res[2], res[3]);
arr = merge(m1, m2);
display("排序后:", arr, "");
} catch (Exception e) {
e.printStackTrace();
}
pool.shutdown();//关闭线程池
}
public static int[] merge(int[] a, int[] b) {
int la = a.length, lb = b.length;
int i = 0, j = 0, index = 0;
int res[] = new int[la + lb];
while (i < la && j < lb) {
res[index++] = a[i] <= b[j] ? a[i++] : b[j++];
}
while (i < la) {
res[index++] = a[i++];
}
while (j < lb) {
res[index++] = b[j++];
}
return res;
}
public static void display(String prefix, int[] arr, String suffix) {
System.out.print(prefix);
for (int i = 0; i < arr.length; i++) {
if (i % 20 == 0) System.out.println();
System.out.print(arr[i] + " ");
}
System.out.println(suffix);
}
}
同样分组完后在对数据处理,由于差不多所以直接看代码吧
具体线程实现
package advance2;/*
* @Author: Gnight
* @Date: 2020/12/17 22:51
* @Description:
*/
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import static java.lang.Character.MIN_VALUE;
public class getMaxThread implements Callable<Integer> {
private int[] arr;
private CountDownLatch count;
public getMaxThread(int[] arr, CountDownLatch count) {
this.arr = arr;
this.count = count;
}
@Override
public Integer call() throws Exception {
if (arr == null || arr.length <= 0) return null;
int max = MIN_VALUE;
for (int i = 0; i < arr.length; i++) {
if (max < arr[i]) max = arr[i];
}
count.countDown();
return max;
}
}
测试类
package advance2;/*
* @Author: Gnight
* @Date: 2020/12/17 22:49
* @Description:
求最大值(多线程)
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.*;
public class getMaxDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//线程数
int threadNum = 4;
System.out.println("创建线程数:" + threadNum);
//创建线程池
ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(threadNum);
int[] arr = new int[20];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * 1000);
}
//初始化后的数组为
display("初始化:", arr);
ArrayList<Integer> list = new ArrayList<Integer>();
CountDownLatch count = new CountDownLatch(threadNum);
for (int i = 0; i < threadNum; i++) {
int[] subArray = Arrays.copyOfRange(arr, i * arr.length / threadNum, (i + 1) * arr.length / threadNum);
Future<Integer> future = pool.submit(new getMaxThread(subArray, count));
list.add(future.get());
}
count.await();//等待都搞定
int max = list.get(0);
for (int i = 1; i < list.size(); i++) {
if (max < list.get(i)) max = list.get(i);
}
System.out.println("\n最大值为:" + max);
pool.shutdown();
}
public static void display(String prefix, int[] arr) {
System.out.print(prefix);
for (int i = 0; i < arr.length; i++) {
if (i % 20 == 0) System.out.println();
System.out.print(arr[i] + " ");
}
}
}
这个要注意的就是线程安全,可以采用阻塞队列来实现
定义产品类
package advance3;/*
* @Author: Gnight
* @Date: 2020/12/17 23:05
* @Description:
产品
*/
public class Product {
private String name;
public Product(String name) {
this.name = name;
}
@Override
public String toString() {
return "Product{" +
"name='" + name + '\'' +
'}';
}
}
主要类
package advance3;/*
* @Author: Gnight
* @Date: 2020/12/17 23:01
* @Description:
生产者与消费者模型
*/
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
public class JavaDemo {
public static void main(String[] args) {
//线程安全的队列
LinkedBlockingQueue<Product> queue = new LinkedBlockingQueue<>();
//生成着
for (int i = 0; i < 3; i++) {
new Thread(() -> {
while (true) {
Product product = new Product(UUID.randomUUID().toString());
queue.add(product);
System.out.println(Thread.currentThread().getName() + " 生产了新产品:" + product.toString());
try {
Thread.currentThread().sleep(1000);//生产完休息一下
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "线程 " + String.valueOf(i)).start();
}
//消费者
for (int i = 0; i < 5; i++) {
new Thread(() -> {
while (true) {
Product product = queue.poll();
if (product != null)
System.out.println(Thread.currentThread().getName() + " 消费了产品:" + product.toString());
try {
Thread.currentThread().sleep(2000);//消费完休息一下
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "线程 " + String.valueOf(i)).start();
}
}
}