多執行緒基礎應用
本文講述簡單的多執行緒應用:
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();
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/237228.html
標籤:java
上一篇:面向物件(二)-搞定她-搞定程式
下一篇:演算法題:旋轉影像
