4

这是 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.

我的电脑有问题吗,或者线程应该这么奇怪?

4

2 回答 2

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 声明为一个实际上应该是局部变量的字段。您可以在我的输出中看到这种影响计算的方式(一个线程的总和被另一个线程修改,依此类推。)

于 2013-07-06T09:21:22.963 回答
3

我的电脑有问题吗,或者线程应该这么奇怪?

不,您的系统绝对没问题。是的,线程应该是这样奇怪的。现在,程序的这个输出有很多可能的原因:

  1. 数组的大小非常小。因此,在 cpu 周期可以移交给其他线程之前,操作执行得如此之快。
  2. 没有Thread.sleep()withinsumArray方法可以强制当前线程暂时离开执行并让其他线程获取 cpu 周期。
  3. 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();
      ....
于 2013-07-06T09:40:52.123 回答