Java 代码要求;同步的;没有它也行
这是一个来自Herbert Schildt的Java基础知识的程序,用于演示同步。方法Java 代码要求;同步的;没有它也行,java,multithreading,synchronization,Java,Multithreading,Synchronization,这是一个来自Herbert Schildt的Java基础知识的程序,用于演示同步。方法sumArray(int[])是同步的,这是程序正常工作的要求。然而,当我删除synchronized关键字时,出乎意料地,程序显示了几乎相同的输出,并且仍然给出了正确的结果。 这是节目 class SumArray { private int sum; int sumArray(int[] nums) { sum = 0; // Reset sum.
sumArray(int[])
是同步的
,这是程序正常工作的要求。然而,当我删除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();
}
}
}
我的计算机有什么问题吗,或者线程应该如此奇怪吗?你的问题是你有一个非常小的数组
int[]a=newint[]{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声明为一个字段,它实际上应该是一个局部变量。您可以在我的输出中看到这如何影响计算(一个线程的总和被另一个线程修改,依此类推)
我的电脑有问题吗,或者线程应该是这么奇怪吗
不,你的系统绝对好。是的,线应该是这么奇怪。现在,您的程序的这种输出可能有很多原因:
数组的大小非常小。因此,在cpu周期可以移交给其他线程之前,操作执行得非常快
sumArray
方法中没有Thread.sleep()
,该方法可以强制当前线程暂时停止执行,并让其他线程获得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;
}
再尝试几次不同步地运行它。您可能会看到您的结果发生变化。这是因为您无法保证哪个线程将在任何特定时间访问该方法。它可以像你看到的那样被订购,也可以不订购。我已经运行了大约25次,但仍然得到相同的输出。Putthread.sleep(1000)代码>后SumThread mt2=新的SumThread(“Thread#2”,a)
并大幅增加数组中的元素数……这可能会给您带来效果。我尝试了您的建议,但仍然是一样的。线程#1在线程#2开始之前完成。有10000个元素,请关注结果。这是一个巨大的控制台输出,确保你没有遗漏任何东西。JVM很可能会让其他线程在第一个线程完成之前运行。然而,要理解的想法是,当不同步时,您无法控制它。将总和声明为局部变量将如何使OP看到不同的输出?什么??请参阅我的输出:线程2:1,然后是5,而不是预期的3。因为线程1已经修改了总和。我说它应该是本地的,不能被其他线程修改。现在它是一个类字段,线程之间共享一个isntance。请注意您是对的,在for循环中调用Thread.sleep()
,会产生不同。
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();
....