Java使用5個線程計算數(shù)組之和
前言
之前寫過多線程累加計數(shù),原理跟本篇類似,傳送門
累加計數(shù)比計算數(shù)組之和邏輯稍微簡單一點,如果對于這塊不熟悉的,可以先看下累加計數(shù)。
基本思想已經(jīng)在之前那篇文章里寫過了,這里就直接貼代碼了。
這里分別通過自己創(chuàng)建線程來實現(xiàn)功能,還有通過線程池來實現(xiàn)功能。思想都差不多。只是代碼寫法略有不同。僅供參考。
代碼一:
五個線程交替累加計算數(shù)組之和,這種方法其實不如單線程直接累加快,因為交替累加需要前一個線程計算的結(jié)果。
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FiveThreadCount {
private int count=0;
private int[] arr={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28};
private int j=0;
//定義一個任務(wù),關(guān)鍵點所在
private class MyThread extends Thread{
@Override
public void run() {
super.run();
while(j<arr.length)
{
synchronized (MyThread.class) {
if(j>=arr.length){
return;
}
count+=arr[j++];
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}
}
//方法一
public void test1(){
for(int i=0;i<5;i++){
new MyThread().start();
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(count);
}
//方法二
public void test2(){
Thread myThread=new MyThread();
for(int i=0;i<5;i++){
new Thread(myThread).start();
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(count);
}
//方法一的線程池實現(xiàn)版
public void test3(){
ExecutorService service=Executors.newCachedThreadPool();
for(int i=0;i<5;i++){
service.execute(new MyThread());
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(count);
}
//方法二的線程池實現(xiàn)版
public void test4(){
ExecutorService service=Executors.newCachedThreadPool();
Thread myThread=new MyThread();
for(int i=0;i<5;i++){
service.execute(myThread);
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(count);
}
}
上邊代碼中,用到了sleep方法的原因,sleep(100)是為了讓其他線程有時間執(zhí)行任務(wù),如果不sleep的話,有可能一個線程就全部執(zhí)行完了。 最后的sleep(10000)是為了等所有線程執(zhí)行完后,打印最后的計算結(jié)果。
代碼二:
將數(shù)組分為5等分,讓每個線程計算自己負(fù)責(zé)的那份,并發(fā)計算,最后匯總結(jié)果。這種方式比代碼一速度會快些。因為線程獨立計算,不依賴其他線程的結(jié)果。最后幾個線程將總數(shù)累加即可。
方式一:
使用Callable,F(xiàn)utureTask方式,來實現(xiàn)代碼:
package test;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
public class FiveThreadCount2 {
private int[] arr={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28};
private int total=0;
public void test() throws InterruptedException, ExecutionException{
ExecutorService service=Executors.newFixedThreadPool(5);
int length=arr.length;
for(int j=0;j<length;j+=(length/5)){
FutureTask<Integer> task;
if( (j+(length/5))<length){
task=new FutureTask<Integer>(new MyCallable(arr, j, j+(length/5)));
}else{
task=new FutureTask<Integer>(new MyCallable(arr, j, length));
}
service.execute(task);
total+=task.get();
}
service.shutdown();
System.out.println(total);
}
public class MyCallable implements Callable<Integer>{
int[] arr;
int startIndex;
int endIndex;
public MyCallable(int[] arr,int startIndex,int endIndex){
this.arr=arr;
this.startIndex=startIndex;
this.endIndex=endIndex;
}
@Override
public Integer call() throws Exception {
int sum=0;
for(int i=startIndex;i<endIndex;i++){
sum+=arr[i];
}
System.out.println(Thread.currentThread().getName());
return sum;
}
}
}
這個方式有一個缺點,看似5個線程異步執(zhí)行,其實是順序執(zhí)行,因為 task.get是要等待線程執(zhí)行完畢才會執(zhí)行下邊的代碼。所以效率不會高,可能換種寫法可以解決這個問題,這里就不深入研究。
方式二:
通過java工具類CountDownLatch實現(xiàn)并發(fā)計算
package test;
import java.util.concurrent.CountDownLatch;
public class FiveThreadCount3 {
private int[] arr={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28};
private int total=0;
public void test() throws InterruptedException{
int length=arr.length;
CountDownLatch latch=new CountDownLatch(length%5==0?5:6);
System.out.println(length);
for(int j=0;j<length;j+=(length/5)){
MyThread task;
if( (j+(length/5))<=length){
task=new MyThread(arr, j, j+(length/5), latch);
}else{
task=new MyThread(arr, j, length, latch);
}
new Thread(task).start();
}
latch.await();
System.out.println(total);
}
private class MyThread implements Runnable{
int[] arr;
int startIndex;
int endIndex;
CountDownLatch latch;
public MyThread(int[] arr,int startIndex,int endIndex,CountDownLatch latch){
this.arr=arr;
this.startIndex=startIndex;
this.endIndex=endIndex;
this.latch=latch;
}
@Override
public void run() {
int sum=0;
for(int i=startIndex;i<endIndex;i++){
sum+=arr[i];
}
synchronized (MyThread.class) {
total+=sum;
}
System.out.println(Thread.currentThread().getName());
latch.countDown();
}
}
}
對于CountDownLatch不熟悉的可以搜索下用法。
方式三:
通過java工具類 CyclicBarrier實現(xiàn)并發(fā)計算。
package test;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class FiveThreadCount1 {
private int[] arr={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28};
private int total=0;
public void test() throws InterruptedException, BrokenBarrierException{
int length=arr.length;
CyclicBarrier barrier=new CyclicBarrier((length%5==0?5:6)+1);
System.out.println(length);
for(int j=0;j<length;j+=(length/5)){
MyThread task;
if( (j+(length/5))<=length){
task=new MyThread(arr, j, j+(length/5), barrier);
}else{
task=new MyThread(arr, j, length, barrier);
}
new Thread(task).start();
}
barrier.await();
System.out.println(total);
}
private class MyThread implements Runnable{
int[] arr;
int startIndex;
int endIndex;
CyclicBarrier barrier;
public MyThread(int[] arr,int startIndex,int endIndex,CyclicBarrier barrier){
this.arr=arr;
this.startIndex=startIndex;
this.endIndex=endIndex;
this.barrier=barrier;
}
@Override
public void run() {
int sum=0;
for(int i=startIndex;i<endIndex;i++){
sum+=arr[i];
}
synchronized (MyThread.class) {
total+=sum;
}
try {
System.out.println(Thread.currentThread().getName());
barrier.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
總結(jié)
總體來說,代碼二的方式二、三,效率會高一點。以上代碼都是通過main方法調(diào)用示例代碼的test方法,輸出結(jié)果到控制臺。
到此這篇關(guān)于Java使用5個線程計算數(shù)組之和的文章就介紹到這了,更多相關(guān)Java 線程數(shù)組之和內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot中注解@ConfigurationProperties與@Value的區(qū)別與使用詳解
本文主要介紹了SpringBoot中注解@ConfigurationProperties與@Value的區(qū)別與使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09
學(xué)會IDEA REST Client后就可以丟掉postman了
這篇文章主要介紹了學(xué)會IDEA REST Client后就可以丟掉postman了,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
Spring Boot Admin 動態(tài)修改日志級別的方法步驟
這篇文章主要介紹了Spring Boot Admin 動態(tài)修改日志級別的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
詳解ConcurrentHashMap如何保證線程安全及底層實現(xiàn)原理
這篇文章主要為大家介紹了ConcurrentHashMap如何保證線程安全及底層實現(xiàn)原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
解決一個JSON反序列化問題的辦法(空字符串變?yōu)榭占?
在平時的業(yè)務(wù)開發(fā)中,經(jīng)常會有拿到一串序列化后的字符串要來反序列化,下面這篇文章主要給大家介紹了如何解決一個JSON反序列化問題的相關(guān)資料,空字符串變?yōu)榭占?需要的朋友可以參考下2024-03-03
Java中的HashMap弱引用之WeakHashMap詳解
這篇文章主要介紹了Java中的HashMap弱引用之WeakHashMap詳解,當(dāng)內(nèi)存空間不足,Java虛擬機寧愿拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內(nèi)存不足的問題,需要的朋友可以參考下2023-09-09

