用多线程对2万个整数的数组计算和,并得到结果。具体题目
计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。
常见问题
用下面博主写的没有方法的代码运行就会发现问题。运行多次后,会发现最终得到的结果不一样,并且不正确。这就是多线程互相争抢资源的结果,那么我们怎么来把这个问题简单的解决一下了。下面就是博主对这个问题的解答过程。
多线程的创建方式:两种方法Runnable接口,自己创建一个类实现Runnable接口。
Thad类,自己创建一个类继承Thad类,通过创建对象。方法一:Runnable接口
我们通过三种方法(睡眠、合并、判断)来解决线程间抢资源的问题,会发现,睡眠:Thad.slee(1000(1秒)延迟的时间):这样子线程就有足够的时间来完成运算。缺点:对于时间的掌握不准确,有可能浪费时间或者时间不够。ubcclasstest{
ubcstaticvoidmain(String[]args)throwsInterrutedExcetion{
**
*计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。
*
int[]cs=newint[20000];
for(inti=0;i<cs.length;i++){
cs[i]=i+1;为什么加1:因为i是下标,起始值为0,我们输入的值从1开始,所有加1
}
创建实现类对象
Tesktesk1=newTesk(1,5000,cs);
Tesktesk2=newTesk(5001,10000,cs);
Tesktesk3=newTesk(10001,15000,cs);
Tesktesk4=newTesk(15001,20000,cs);
创建子线程对象
Thadt1=newThad(tesk1);
Thadt2=newThad(tesk2);
Thadt3=newThad(tesk3);
Thadt4=newThad(tesk4);
线程启动:开始运行
t1.start();
t2.start();
t3.start();
t4.start();
方式一:睡眠:给子线程足够的时间计算,但是浪费时间。
Thad.slee(1000); 延迟1000毫秒
System.out.rintln(tesk1.getsum()+tesk2.getsum()+tesk3.getsum()+tesk4.getsum());
}
}
classTeskimlementsRunnable{
rivateintstartnum;开始数
rivateintendnum;结尾数
rivateintsum;和
rivateint[]is;数组
rivateboeanflag=true; ubcTesk(intstartnum,intendnum,int[]is){
this.startnum=startnum;
this.endnum=endnum;
this.is=is;
}
重写Runnable中的run方法
@Override
ubcvoidrun(){
for(inti=startnum;i<=endnum;i++){
this.sum+=is[i-1];
}flag=false;
}
因为是私有属性,所有通过一个方法来返回sum(计算和的结果)
ubcintgetsum(){返回出各线程的计算和值
turnthis.sum;
}
}
判断:通过在MyThad类里面加flag(来判断),在主函数里通过while(这里就有朋友问了,为啥不用if来做判断,if条件是不满足时也会往下运行,而while只会一直循环,直到满足条件后,才会执行下面的代码)来判断子线程是否运行完成。完成就执行主函数的代码。ubcclasstest{
ubcstaticvoidmain(String[]args)throwsInterrutedExcetion{
int[]cs=newint[20000];
for(inti=0;i<cs.length;i++){
cs[i]=i+1;为什么加1:因为i是下标,起始值为0,我们输入的值从1开始,所有加1
}
创建实现类对象
Tesktesk1=newTesk(1,5000,cs);
Tesktesk2=newTesk(5001,10000,cs);
Tesktesk3=newTesk(10001,15000,cs);
Tesktesk4=newTesk(15001,20000,cs);
创建子线程对象
Thadt1=newThad(tesk1);
Thadt2=newThad(tesk2);
Thadt3=newThad(tesk3);
Thadt4=newThad(tesk4);
线程启动:开始运行
t1.start();
t2.start();
t3.start();
t4.start();
方法二:
while(tesk1.isflag()||tesk2.isflag()||tesk3.isflag()||tesk4.isflag()){当每一个线程都运行完时,就会返回
}
System.out.rintln(tesk1.getsum()+tesk2.getsum()+tesk3.getsum()+tesk4.getsum());
}
}
classTeskimlementsRunnable{
rivateintstartnum;开始数
rivateintendnum;结尾数
rivateintsum;和
rivateint[]is;数组
rivateboeanflag=true;判断,现在状态为trueubcTesk(intstartnum,intendnum,int[]is){
this.startnum=startnum;
this.endnum=endnum;
this.is=is;
}
重写Runnable中的run方法
@Override
ubcvoidrun(){
for(inti=startnum;i<=endnum;i++){
this.sum+=is[i-1];
}flag=false; 运行完后就给flag赋值false;
}
因为是私有属性,所有通过一个方法来返回sum(计算和的结果)
ubcintgetsum(){返回出各线程的计算和值
turnthis.sum;
}
ubcboeanisflag(){返回flag的状态
turnflag;
}
}
合并:(推荐)大概的意思就是把我们想要先执行的代码,嵌入到主函数中,这样主函数执行时,就会先执行我们插入的代码块。这种也不会浪费时间,也不需要做多余的代码操作。博主推荐新手可以用这种方法,比较好理解代码量也比较少。ubcclasstest{
ubcstaticvoidmain(String[]args)throwsInterrutedExcetion{
int[]cs=newint[20000];
for(inti=0;i<cs.length;i++){
cs[i]=i+1;为什么加1:因为i是下标,起始值为0,我们输入的值从1开始,所有加1
}
创建实现类对象
Tesktesk1=newTesk(1,5000,cs);
Tesktesk2=newTesk(5001,10000,cs);
Tesktesk3=newTesk(10001,15000,cs);
Tesktesk4=newTesk(15001,20000,cs);
创建子线程对象
Thadt1=newThad(tesk1);
Thadt2=newThad(tesk2);
Thadt3=newThad(tesk3);
Thadt4=newThad(tesk4);
线程启动:开始运行
t1.start();
t2.start();
t3.start();
t4.start();
方法三:合并join方法为合并
t1.join();
t2.join();
t3.join();
t4.join();
System.out.rintln(tesk1.getsum()+tesk2.getsum()+tesk3.getsum()+tesk4.getsum());
}
}
classTeskimlementsRunnable{
rivateintstartnum;开始数
rivateintendnum;结尾数
rivateintsum;和
rivateint[]is;数组
ubcTesk(intstartnum,intendnum,int[]is){
this.startnum=startnum;
this.endnum=endnum;
this.is=is;
}
重写Runnable中的run方法
@Override
ubcvoidrun(){
for(inti=startnum;i<=endnum;i++){
this.sum+=is[i-1];
}flag=false; 运行完后就给flag赋值false;
}
因为是私有属性,所有通过一个方法来返回sum(计算和的结果)
ubcintgetsum(){返回出各线程的计算和值
turnthis.sum;
}
}方法二:Thad类
此方法也是和上面的方法也是一样,只是不用实现接口了,直接在主函数里面new对象,那么在这简单描述一下。
ubcclassWork{
ubcstaticvoidmain(String[]args)throwsInterrutedExcetion{
声明包含2万个整数的数组
int[]is=newint[20000];
初始化数据
for(inti=0;i<is.length;i++){
is[i]=(i+1);
}
MyThadt1=newMyThad(0,4999,is);
MyThadt2=newMyThad(5000,9999,is);
MyThadt3=newMyThad(10000,14999,is);
MyThadt4=newMyThad(15000,19999,is);
t1.start();
t2.start();
t3.start();
t4.start();
数据错误的原因:4个子线程还没有执行完毕,主线程就抢到资源并输出结果
解决方案:4个子线程全部执行完毕,再让主线程抢到资源
1.休眠
Thad.slee(10);
2.获取线程状态
while(t1.isFlag()||t2.isFlag()||t3.isFlag()||t4.isFlag()){
}
3.合并
t1.join();
t2.join();
t3.join();
t4.join();
System.out.rintln(t1.getSum()+t2.getSum()+t3.getSum()+t4.getSum());
}
}
classMyThadextendsThad{
rivateintstartIndex;
rivateintendIndex;
rivateint[]is;
rivateintsum;
rivateboeanflag=true;
ubcMyThad(intstartIndex,intendIndex,int[]is){
this.startIndex=startIndex;
this.endIndex=endIndex;
this.is=is;
} @Override
ubcvoidrun(){
for(inti=startIndex;i<=endIndex;i++){
sum+=is[i];
}
flag=false;
} ubcintgetSum(){
turnsum;
} ubcboeanisFlag(){
turnflag;
}
}