这是来自Herbert Schildt的Java Fundamentals的程序,用于演示同步。方法sumArray(int[])
是synchronized
,这是程序正常工作的要求。但是,当我意外删除synchronized
关键字时,程序显示几乎相同的输出,仍然给出了正确的结果。
这是该计划。
class SumArray {
private int sum;
int sumArray(int[] nums) {
sum = 0; // Reset sum.
for(int i = 0; i < nums.length; i++) {
sum += nums[i];
System.out.println("Running total for " + Thread.currentThread().getName() + " is " + sum);
}
return sum;
}
}
class SumThread implements Runnable {
static SumArray sa = new SumArray();
Thread thrd;
int[] a;
int answer;
public SumThread(String name, int[] nums) {
thrd = new Thread(this, name);
a = nums;
thrd.start();
}
@Override public void run() {
System.out.println(thrd.getName() + " starting.");
answer = sa.sumArray(a);
System.out.println("Sum for " + thrd.getName() + " is " + answer);
System.out.println(thrd.getName() + " terminating.");
}
}
public class SyncExample {
public static void main(String[] args) {
int[] a = new int[] {1, 2, 3, 4, 5, 6};
SumThread mt1 = new SumThread("Thread #1", a);
SumThread mt2 = new SumThread("Thread #2", a);
try {
mt1.thrd.join();
mt2.thrd.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
输出
Thread #1 starting.
Running total for Thread #1 is 1
Running total for Thread #1 is 3
Running total for Thread #1 is 6
Running total for Thread #1 is 10
Running total for Thread #1 is 15
Running total for Thread #1 is 21
Sum for Thread #1 is 21
Thread #1 terminating.
Thread #2 starting.
Running total for Thread #2 is 1
Running total for Thread #2 is 3
Running total for Thread #2 is 6
Running total for Thread #2 is 10
Running total for Thread #2 is 15
Running total for Thread #2 is 21
Sum for Thread #2 is 21
Thread #2 terminating.
我的电脑有问题,或者线程应该是这么奇怪吗?
答案 0 :(得分:6)
问题是你有一个非常小的数组int[] a = new int[] {1, 2, 3, 4, 5, 6};
。
线程1在线程2开始之前完成。
如果您尝试使用10000或更多元素的数组运行,您可能会看到差异。
我用10000个元素运行你的代码:
线程#1开始。
线程#2开始。
线程#1的运行总计为1
线程#2的运行总计为1
线程#1的运行总计为3
线程#2的运行总计为5
线程#2的运行总计为11
线程#2的运行总计为15
线程#1的运行总计为8
..........
因此,即使你的机器显示顺序执行的线程 - 也不能保证它会在每台机器和每次程序启动时都这样。
此外,还有一个错误:
修改强>
您已将sum声明为一个字段,该字段实际上应该是一个局部变量。您可以在我的输出中看到此效果计算(一个线程的总和由另一个线程修改,依此类推。)
答案 1 :(得分:3)
我的电脑有问题,或者线程应该是这么奇怪吗?
不,你的系统绝对没问题。是线程应该是这么奇怪。现在,您的程序输出有很多可能的原因:
Thread.sleep()
方法中没有sumArray
可以强制当前线程离开执行一段时间,让其他线程获得cpu周期。mt1.thrd.join();
在mt2.thrd
启动之前执行。这会强制所有线程等到mt1.thrd
完成执行。如何查看非同步行为?
进行以下更改:
int sumArray(int[] nums) {
sum = 0; // Reset sum.
for(int i = 0; i < nums.length; i++) {
sum += nums[i];
try{
Thread.sleep(100);//Make the current thread to sleep for 100 ms
}catch(Exception ex){ex.printStackTrace();}
System.out.println("Running total for " + Thread.currentThread().getName() + " is " + sum);
}
return sum;
}
然后另一个改变:
int[] a = new int[400];//increase the size of array
for (int i = 0 ; i < a.length ; i++)
a[i] = i;
然后,
SumThread mt2 = new SumThread("Thread #2", a);
try{
Thread.sleep(1000);//make to main thread to sleep before mt1.thrd.join() could be called.
}catch(Exception ex){ex.printStackTrace();}
try {
mt1.thrd.join();
....