我正在做一个涉及线程的简单练习。
(a)创建一个名为SumAction的类,它实现了Runnable。 该类包含3个实例变量 - start,end和sum。 start和end由构造函数初始化。 sum设置为0.
(b)run()方法应该有一个for循环,它应该找到从开始到结束的所有值的总和。应该有一个方法getSum()来返回sum的值。
(c)在主要创建此Runnable类的2个实例中,一个以1和10作为参数,另一个需要10和20。
(d)将这些实例传递给2个线程构造函数,以创建线程t1和t2。
(e)线程完成后,调用getSum从两个线程中获取总和值以查找总数。
我很确定我这样做是正确的,但我仍然得到0的总和值。
这是我的班级
public class SumAction implements Runnable {
private int start, end, sum;
public SumAction(int start, int end) {
this.start = start;
this.end = end;
sum = 0;
}
@Override
public void run()
{
for (int i = start+1; i < end; i++)
{
sum += i;
}
}
public int getSum() {
return sum;
}
}
这是主要的
SumAction run1 = new SumAction(1, 10);
SumAction run2 = new SumAction(10, 20);
Thread t1= new Thread(run1);
Thread t2= new Thread(run2);
t1.start();
t2.start();
System.out.println("Sum 1 : " + run1.getSum());
System.out.println("Sum 2 : " + run2.getSum());
答案 0 :(得分:8)
你不等待线程完成。你的主线程可以在其他线程完成计算之前或甚至在它们开始之前调用getSum。此外,即使线程确实在println之前完成,主线程也可能看不到更新的值。
在线程上调用join以等待它们完成,在启动线程之后和printlns之前添加它:
t1.join();
t2.join();
这确保主线程在尝试打印总和之前等待其他线程完成,并且还会处理可见性问题。
在许多情况下,如果有足够的预防措施(同步,使字段不稳定等),从另一个线程写入的字段中读取线程是有问题的(错误,依赖于实现,或者只是令人困惑且难以推理)没有被采取。但是在这段代码中,如果你调用join,那么主线程不需要额外的同步来确保看到getSum的最新值,因为有一个适用的before-before规则。引自Oracle tutorial:
当一个线程终止并导致另一个线程中的Thread.join返回时,终止线程执行的所有语句与成功连接后的所有语句都有一个before-before关系。现在,执行连接的线程可以看到线程中代码的效果。
join方法抛出InterruptedException,如果线程在设置了中断标志后进入休眠或等待状态,则抛出一个已检查的异常。对于一个简单的示例程序,您实际上没有中断任何内容,可以将它添加到main方法的throws子句中。