这是我的代码:
/* User: koray@tugay.biz Date: 21/02/15 Time: 19:53 */
public class DriverClass {
public static void main(String[] args) throws InterruptedException {
int upper = 15;
Integer sumValue = null;
Thread thread = new Thread(new Summation(upper, sumValue));
thread.start();
thread.join();
System.out.println(sumValue);
}
}
和Summation类:
class Summation implements Runnable {
private int upper;
private Integer sumValue;
public Summation(int upper, Integer sumValue) {
this.upper = upper;
this.sumValue = sumValue;
}
public void run() {
System.out.println("Thread started...");
int sum = 0;
for (int i = 0; i <= upper; i++) {
sum += i;
}
System.out.println("Sum is:" + sum);
sumValue = sum;
}
}
我将在控制台中看到:
Thread started...
Sum is:120
null
为什么最后一行是&#39; null&#39; ?我期待再次看到120?
答案 0 :(得分:4)
行。让我用图片解释一下。首先在main方法中创建一个引用并为其赋值null:
main
----
sumValue -----> null
然后将此引用传递给Summation构造函数。这将创建引用的副本:
main
----
sumValue -----> null
^
Summation |
---- |
sumValue --------
然后Summation.run()emthod为Summation.sumValue引用分配一个新的整数值:
main
----
sumValue -----> null
Summation
----
sumValue -----> 120
如您所见,main方法中的引用仍指向null
。这就是打印null的原因。
相反,您可以做的是传递对可变对象的引用,该对象的状态可以更改(例如AtomicInteger):
main
----
sumValue -----> AtomicInteger(0)
然后将其传递给Summation:
main
----
sumValue -----> AtomicInteger(0)
^
Summation |
---- |
sumValue --------
然后在Summation中,修改AtomicInteger的状态:sumValue.set(120)
:
main
----
sumValue -----> AtomicInteger(120)
^
Summation |
---- |
sumValue --------
然后,当在main方法中打印AtomicInteger时,你将有120,因为那时main方法和Summation对象有两个指向同一对象的引用。
或者更好的是,您可以将结果存储为Summation对象中的Integer,并在计算完成后在main方法中询问结果:
System.out.println(summation.getSumValue());
答案 1 :(得分:2)
这是因为Integer是不可变的。
您正在通过构造函数将sumValue传递给Summation,但是在构造函数中创建了一个新的Integer来复制您传递给它的值。
为了更好地理解这里发生的事情,您可能需要查看this article,请记住您正在使用不可变对象(您的Integer对象)
编辑:
创建自己的类扩展Integer?看看这个immutable class should be final?
您可以为sumValue创建一个访问者getter:
public class DriverClass {
public static void main(String[] args) throws InterruptedException {
int upper = 15;
Integer sumValue = null;
Summation sum = new Summation(upper, sumValue);
Thread thread = new Thread(sum);
thread.start();
thread.join();
sumValue = sum.getSumValue();
System.out.println(sumValue);
}
}
class Summation implements Runnable {
private final int upper;
private Integer sumValue;
public Summation(int upper, Integer sumValue) {
this.upper = upper;
this.sumValue = sumValue;
}
@Override
public void run() {
System.out.println("Thread started...");
int sum = 0;
for (int i = 0; i <= upper; i++) {
sum += i;
}
System.out.println("Sum is:" + sum);
sumValue = sum;
}
public Integer getSumValue() {
return sumValue;
}
}
答案 2 :(得分:1)
在Summation
的构造函数中,您设置了字段sumValue
。
然后在函数run
中再次设置字段sumValue
:
sumValue = sum;
但是您要将字段设置为新的Integer
实例。您没有将旧的Integer实例设置为新值。
这就是为什么主线程中的sumValue
没有变化,除了null
之外,它从未被设置为任何东西。
答案 3 :(得分:1)
在线程内部,您将SumValue分配给新的Object,因此在线程外部它仍为null。如果您计划多次运行此线程以获得多个总和,请尝试将总和存储在Map中,其中键是较大的数字,值是总和。
所以:
Map<Integer,Integer> sumMap = new TreeMap<Integer,Integer>();
Thread thread = new Thread(new Summation(upper, sumMap));
public Summation(int upper, Map<Integer,Integer> sumMap) {
this.upper = upper;
this.sumMap= sumMap;
}
public void run() {
System.out.println("Thread started...");
int sum = 0;
for (int i = 0; i <= upper; i++) {
sum += i;
}
System.out.println("Sum is:" + sum);
sumMap.put(upper,sum);
}
答案 4 :(得分:1)
此代码
sumValue = sum;
使用新引用覆盖Summation
的{{1}},而不是更新已存在的引用值。
如果您想从某个帖子返回值,则需要使用Callable
而不是sumValue
。
但是,Runnable
s不能直接使用Thread。相反,您必须使用ExecutorService
。
最简单的方法是:
Callable
请注意,这会使用Future<Integer>
,这是将来会返回的值。除非ExecutorService service = Executors.newSingleThreadExecutor();
Future<Integer> future = service.submit(new Summation());
Integer sumValue = future.get(); // The Future equivalent of join
完成处理,否则我们使用get
阻止。
请注意,您必须重新设计Summation才能实现Future
而不是Callable<Integer>
,并将Runnable
更改为public void run()
和public Integer call()
(或return sum;
)。