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.

这是一个来自Herbert Schildt的Java基础知识的程序,用于演示同步。方法
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次,但仍然得到相同的输出。Put
    thread.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();
          ....