用多线程对2万个整数的数组计算和,并得到结果。
计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。
用下面博主写的没有方法的代码运行就会发现问题。运行多次后,会发现最终得到的结果不一样,并且不正确。这就是多线程互相争抢资源的结果,那么我们怎么来把这个问题简单的解决一下了。下面就是博主对这个问题的解答过程。
我们通过三种方法(睡眠、合并、判断)来解决线程间抢资源的问题,会发现, 睡眠:Thread.sleep(1000(1秒)//延迟的时间):这样子线程就有足够的时间来完成运算。缺点:对于时间的掌握不准确,有可能浪费时间或者时间不够。
public class test {
public static void main(String[] args) throws InterruptedException {
/**
* 计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。
*/
int[] cs = new int[20000];
for (int i = 0; i < cs.length; i++) {
cs[i] = i+1;//为什么加1:因为i是下标,起始值为0,我们输入的值从1开始,所有加1
}
//创建实现类对象
Tesk tesk1 = new Tesk(1,5000,cs);
Tesk tesk2 = new Tesk(5001,10000,cs);
Tesk tesk3 = new Tesk(10001,15000,cs);
Tesk tesk4 = new Tesk(15001,20000,cs);
//创建子线程对象
Thread t1 = new Thread(tesk1);
Thread t2 = new Thread(tesk2);
Thread t3 = new Thread(tesk3);
Thread t4 = new Thread(tesk4);
//线程启动:开始运行
t1.start();
t2.start();
t3.start();
t4.start();
//方式一:睡眠:给子线程足够的时间计算,但是浪费时间。
Thread.sleep(1000); //延迟1000毫秒
System.out.println(tesk1.getsum()+tesk2.getsum()+tesk3.getsum()+tesk4.getsum());
}
}
class Tesk implements Runnable{
private int startnum;//开始数
private int endnum;//结尾数
private int sum;//和
private int[] is;//数组
// private boolean flag = true;
public Tesk(int startnum, int endnum, int[] is) {
this.startnum = startnum;
this.endnum = endnum;
this.is = is;
}
//重写Runnable中的run方法
@Override
public void run() {
for (int i = startnum; i <= endnum; i++) {
this.sum +=is[i-1];
}//flag = false;
}
//因为是私有属性,所有通过一个方法来返回sum(计算和的结果)
public int getsum() {//返回出各线程的计算和值
return this.sum;
}
}
判断:通过在MyThread类里面加flag(来判断),在主函数里通过while(这里就有朋友问了,为啥不用if来做判断,if条件是不满足时也会往下运行,而while只会一直循环,直到满足条件后,才会执行下面的代码)来判断子线程是否运行完成。完成就执行主函数的代码。
public class test {
public static void main(String[] args) throws InterruptedException {
int[] cs = new int[20000];
for (int i = 0; i < cs.length; i++) {
cs[i] = i+1;//为什么加1:因为i是下标,起始值为0,我们输入的值从1开始,所有加1
}
//创建实现类对象
Tesk tesk1 = new Tesk(1,5000,cs);
Tesk tesk2 = new Tesk(5001,10000,cs);
Tesk tesk3 = new Tesk(10001,15000,cs);
Tesk tesk4 = new Tesk(15001,20000,cs);
//创建子线程对象
Thread t1 = new Thread(tesk1);
Thread t2 = new Thread(tesk2);
Thread t3 = new Thread(tesk3);
Thread t4 = new Thread(tesk4);
//线程启动:开始运行
t1.start();
t2.start();
t3.start();
t4.start();
//方法二:
while (tesk1.isflag() || tesk2.isflag() || tesk3.isflag() || tesk4.isflag()) {//当每一个线程都运行完时,就会返回
}
System.out.println(tesk1.getsum()+tesk2.getsum()+tesk3.getsum()+tesk4.getsum());
}
}
class Tesk implements Runnable{
private int startnum;//开始数
private int endnum;//结尾数
private int sum;//和
private int[] is;//数组
private boolean flag = true;//判断,现在状态为true
public Tesk(int startnum, int endnum, int[] is) {
this.startnum = startnum;
this.endnum = endnum;
this.is = is;
}
//重写Runnable中的run方法
@Override
public void run() {
for (int i = startnum; i <= endnum; i++) {
this.sum +=is[i-1];
}flag = false; //运行完后就给flag赋值false;
}
//因为是私有属性,所有通过一个方法来返回sum(计算和的结果)
public int getsum() {//返回出各线程的计算和值
return this.sum;
}
public boolean isflag() {//返回flag的状态
return flag;
}
}
合并:(推荐)大概的意思就是把我们想要先执行的代码,嵌入到主函数中,这样主函数执行时,就会先执行我们插入的代码块。这种也不会浪费时间,也不需要做多余的代码操作。博主推荐新手可以用这种方法,比较好理解代码量也比较少。
public class test {
public static void main(String[] args) throws InterruptedException {
int[] cs = new int[20000];
for (int i = 0; i < cs.length; i++) {
cs[i] = i+1;//为什么加1:因为i是下标,起始值为0,我们输入的值从1开始,所有加1
}
//创建实现类对象
Tesk tesk1 = new Tesk(1,5000,cs);
Tesk tesk2 = new Tesk(5001,10000,cs);
Tesk tesk3 = new Tesk(10001,15000,cs);
Tesk tesk4 = new Tesk(15001,20000,cs);
//创建子线程对象
Thread t1 = new Thread(tesk1);
Thread t2 = new Thread(tesk2);
Thread t3 = new Thread(tesk3);
Thread t4 = new Thread(tesk4);
//线程启动:开始运行
t1.start();
t2.start();
t3.start();
t4.start();
//方法三:合并join方法为合并
t1.join();
t2.join();
t3.join();
t4.join();
System.out.println(tesk1.getsum()+tesk2.getsum()+tesk3.getsum()+tesk4.getsum());
}
}
class Tesk implements Runnable{
private int startnum;//开始数
private int endnum;//结尾数
private int sum;//和
private int[] is;//数组
public Tesk(int startnum, int endnum, int[] is) {
this.startnum = startnum;
this.endnum = endnum;
this.is = is;
}
//重写Runnable中的run方法
@Override
public void run() {
for (int i = startnum; i <= endnum; i++) {
this.sum +=is[i-1];
}flag = false; //运行完后就给flag赋值false;
}
//因为是私有属性,所有通过一个方法来返回sum(计算和的结果)
public int getsum() {//返回出各线程的计算和值
return this.sum;
}
}
此方法也是和上面的方法也是一样,只是不用实现接口了,直接在主函数里面new 对象,那么在这简单描述一下。
public class Work {
public static void main(String[] args) throws InterruptedException {
//声明包含2万个整数的数组
int[] is = new int[20000];
//初始化数据
for (int i = 0; i < is.length; i++) {
is[i] = (i+1);
}
MyThread t1 = new MyThread(0, 4999, is);
MyThread t2 = new MyThread(5000, 9999, is);
MyThread t3 = new MyThread(10000, 14999, is);
MyThread t4 = new MyThread(15000, 19999, is);
t1.start();
t2.start();
t3.start();
t4.start();
//数据错误的原因:4个子线程还没有执行完毕,主线程就抢到资源并输出结果
//解决方案:4个子线程全部执行完毕,再让主线程抢到资源
//1.休眠
// Thread.sleep(10);
//2.获取线程状态
// while(t1.isFlag() || t2.isFlag() || t3.isFlag() || t4.isFlag()){
// }
//3.合并
t1.join();
t2.join();
t3.join();
t4.join();
System.out.println(t1.getSum() + t2.getSum() + t3.getSum() + t4.getSum());
}
}
class MyThread extends Thread{
private int startIndex;
private int endIndex;
private int[] is;
private int sum;
private boolean flag = true;
public MyThread(int startIndex, int endIndex, int[] is) {
this.startIndex = startIndex;
this.endIndex = endIndex;
this.is = is;
}
@Override
public void run() {
for (int i = startIndex; i <= endIndex; i++) {
sum += is[i];
}
flag = false;
}
public int getSum() {
return sum;
}
public boolean isFlag() {
return flag;
}
}