标签:Java,线程,数组
目录
前言
代码一:
代码二:
方式一:
方式二:
方式三:
总结
前言
之前写过多线程累加计数,原理跟本篇类似,传送门
累加计数比计算数组之和逻辑稍微简单一点,如果对于这块不熟悉的,可以先看下累加计数。
基本思想已经在之前那篇文章里写过了,这里就直接贴代码了。
这里分别通过自己创建线程来实现功能,还有通过线程池来实现功能。思想都差不多。只是代码写法略有不同。仅供参考。
代码一:
五个线程交替累加计算数组之和,这种方法其实不如单线程直接累加快,因为交替累加需要前一个线程计算的结果。
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;
//定义一个任务,关键点所在
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);
}
//方法一的线程池实现版
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);
}
//方法二的线程池实现版
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)是为了让其他线程有时间执行任务,如果不sleep的话,有可能一个线程就全部执行完了。 最后的sleep(10000)是为了等所有线程执行完后,打印最后的计算结果。
代码二:
将数组分为5等分,让每个线程计算自己负责的那份,并发计算,最后汇总结果。这种方式比代码一速度会快些。因为线程独立计算,不依赖其他线程的结果。最后几个线程将总数累加即可。
方式一:
使用Callable,FutureTask方式,来实现代码:
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个线程异步执行,其实是顺序执行,因为 task.get是要等待线程执行完毕才会执行下边的代码。所以效率不会高,可能换种写法可以解决这个问题,这里就不深入研究。
方式二:
通过java工具类CountDownLatch实现并发计算
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实现并发计算。
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();
}
}
}
}
总结
总体来说,代码二的方式二、三,效率会高一点。以上代码都是通过main方法调用示例代码的test方法,输出结果到控制台。
来源:https://blog.csdn.net/wzmde007/article/details/89947481


猜你喜欢
- 一、概述在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上咱们可以自己也写一个自定义
- 懒加载 ,也称为嵌套查询 需要查询关联信息时,使用 Mybatis 懒加载特性可有效的减
- 要说在 Spring Boot 中注册过滤器有三种方式,你都能想到哪些呢?今天松哥就来和大家聊一聊 Spring Boot 中注册过滤器的三
- 一、LinkedHashMap的类继承关系二、源码分析1.自己对LinkedHashMap的理解从继承关系上,我们看到LinkedHashM
- 前言作为一个写java的使用最多的轻量级框架莫过于spring,不管是老项目用到的springmvc,还是现在流行的springboot,都
- 我就废话不多说了,大家还是直接看代码吧~ string url = "https://cloud.soei.com.cn/smsa
- __intSumintSum 函数可用于计算两个或多个整数值的总和。引用名称是可选的, 但它不能是有效的整数。{__intSum(2,5,M
- java中Hashmap的get方法map中存储的是键值对,也就是说通过set方法进行参数和值的存储,之后通过get“键”的形式进行值的读取
- Docker是干什么的Docker 是一个基于Linux容器(LXC-linux container)的高级容器引擎,基于go语言开发,源代
- 问题背景: 我要在一个表单里同时一次性提交多名乘客的个人信息到SpringMVC,前端HTML和SpringMVC Controller里该
- 项目中遇到这样个需求:app的功能导航需要可拖动排序,类似头条中的频道拖动管理。效果如下,gif不是很顺畅,真机会好很多。虽然类似的文章网上
- 创建maven父子工程时遇到一个问题,当子工程的名称前缀和父工程的名称一样时,子工程会出现一系列的问题。比如我的父工程名称是microser
- Idea运行单个main方法,不编译整个工程直接上图1、选择main方法类右键->create ‘类名.main&
- 这篇文章主要介绍了SpringMVC的执行流程及组件详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- 先来看看下面List<T>泛型集合的排序例子:using System;using System.Collections.Gen
- 抽象类1.引出抽象类向上转型带来的最大的好处就是参数统一化,使用共同的父类引用,就可以接收所有的子类实例。多态非常依赖方法覆写,但是子类可以
- 一,设计多图片打包下载逻辑:1,如果是要拉取腾讯云等资源服务器的图片,2,我们先把远程图片拉取到本地的临时文件夹,3,然后压缩临时文件夹,4
- 好问题。答案就是这篇文章的题目所建议的,这是一种合理的设计。在这种情况下,newInstance()方法是一种“静态工厂方法",让
- 解决Long型数据转换成json格式时丢失精度最近项目中突然发现雪花算法生成的数据库主键id返回给前端时和本身的值不一致,于是后端进行断点调
- 本文实例讲述了C#实现左截取和右截取字符串的方法,分享给大家供大家参考。具体方法分析如下:问题如下:使用C#语法编写程序时,我们需要截取一个