没有它的代码需要“同步”才能正常工作

时间:2013-07-06 09:16:47

标签: java multithreading synchronization

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

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

2 个答案:

答案 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)

  

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

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

  1. 数组的大小非常小。因此,在将cpu循环移交给其他线程之前,操作执行得如此之快。
  2. Thread.sleep()方法中没有sumArray可以强制当前线程离开执行一段时间,让其他线程获得cpu周期。
  3. mt1.thrd.join();mt2.thrd启动之前执行。这会强制所有线程等到mt1.thrd完成执行。
  4.   

    如何查看非同步行为?

    进行以下更改:

       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();
          ....