简体   繁体   English

Java 中的多线程无法按预期工作

[英]MultiThreading in Java not Working as Expected

The first code does not always show the sum to be 1000, so I figured a way around to fix the problem but why does not the first code work?第一个代码并不总是显示总和为 1000,所以我想了一个方法来解决这个问题,但为什么第一个代码不起作用? The results are highly inconsistent and I know that using synchronized does not serve any purpose in this case, but I was just trying.结果非常不一致,我知道在这种情况下使用 synchronized 没有任何用处,但我只是在尝试。

class Thread1 extends Thread{
    int[] count;
    int[] event;
    Thread1(int[] event, int[] count){
        this.event=event;
        this.count=count;
    }
    public void run(){
        for(int i=0; i<500; i++){

            int x = event[i];
            synchronized (count){
                count[x]++;
            }
        }
    }
}

class Thread2 extends Thread{
    int[] count;
    int[] event;
    Thread2(int[] event, int[] count){
        this.event=event;
        this.count=count;
    }
    public void run(){
        for(int i=500; i<1000; i++){

            int x = event[i];
            synchronized (count){
                count[x]++;
            }

        }
    }
}

public class Learning {

    public static void main(String[] args) {
        Random random = new Random();
        int[] event = new int[1000];

        for(int i=0; i<event.length; i++){
            event[i] = random.nextInt(3);
        }

        Thread1 a = new Thread1(event, new int[3]);
        Thread2 b = new Thread2(event, new int[3]);

        a.start();
        b.start();

        int second = a.count[1]+b.count[1];
        int third = a.count[2]+b.count[2];
        int first = a.count[0]+b.count[0];

        System.out.println(first);
        System.out.println(second);
        System.out.println(third);

        System.out.println("SUM--> "+(first+second+third));
    }
}

WORKS HERE:在这里工作:在此处输入图片说明

DOES NOT WORK HERE不在这里工作在此处输入图片说明

The code sometimes shows a total of 1000 entries, sometimes doesn't.该代码有时显示总共 1000 个条目,有时不显示。 I don't feel there is any need to synchronize as no common resource is being accesed.我觉得没有必要同步,因为没有访问公共资源。

The Thread1 and Thread2 classes use their respective count objects to synchronize.Thread1Thread2类使用各自的count对象进行同步。

The problem is that you instantiate them like this:问题是你像这样实例化它们:

    Thread1 a = new Thread1(event, new int[3]);
    Thread2 b = new Thread2(event, new int[3]);

See?看?

You are passing different arrays to the two threads.您将不同的数组传递给两个线程。 If your two threads use different objects as their count , you do not get mutual exclusion or proper memory visibility.如果您的两个线程使用不同的对象作为它们的count ,则不会获得互斥或适当的内存可见性。


On further examination, it looks like the synchronized block is probably unnecessary anyway.进一步检查,看起来同步块无论如何可能是不必要的。 (You don't need mutual exclusion, and you get certain guarantees that the child threads will see properly initialized arrays because of the start() happens-before .) (您不需要互斥,并且您可以确保子线程将看到正确初始化的数组,因为start()发生在之前。)

However, it is clear that it is necessary to join the two child threads in the main thread for a couple of reasons:但是,很明显,由于以下几个原因,有必要在主线程中join两个子线程:

  1. If you don't join() , you cannot be sure that the child threads have completed before the main thread looks at the results.如果您不join() ,则无法确定子线程在主线程查看结果之前是否已完成。

  2. If you don't join() , there are potential memory anomalies ... even if the child threads have both terminated before the main thread looks at the counts.如果您不join() ,则存在潜在的内存异常……即使子线程在主线程查看计数之前都已终止 (The join() call imposes a happens-before relationship between the child threads and the main thread.) join()调用在子线程和主线程之间强加了一个happens-before关系。)


Your attempted solution using stop() is bogus for the following reasons:由于以下原因,您尝试使用stop()解决方案是虚假的:

  1. The stop() method is deprecated because it is dangerous. stop()方法已被弃用,因为它很危险。 It shouldn't be used.它不应该被使用。

  2. The stop() method doesn't have a specified synchronizing effect. stop()方法没有指定的同步效果。

  3. Based on the documented semantics (such as they are) there is no logical reason that calling stop() should fix the problem.根据记录的语义(例如它们),没有逻辑理由调用stop()应该解决问题。

As a general rule "randomly trying thing" is not a sound strategy for fixing concurrency bugs.作为一般规则,“随机尝试的东西”不是修复并发错误的合理策略。 There is a good chance that a random chance will not fix a bug, but turn it from a bug that occurs frequently to one that occurs rarely ... or only on a different Java platform to the one you test on.很有可能随机的机会不会修复错误,而是将其从经常发生的错误转变为很少发生的错误……或者仅在与您测试的不同的 Java 平台上发生。

Why does it appear to work?为什么它看起来有效?

It looks like the child threads terminated before they stopped.看起来子线程在停止之前就终止了。 But it is just luck that that is happening.但这只是运气。 It is unlikely to happen if you scale up the amount of work that the child threads do.如果您扩大子线程所做的工作量,则不太可能发生这种情况。

adding - a.stop();添加 - a.stop(); b.stop(); b.停止(); after a.start();之后 a.start(); b.start(); b.开始(); fixes the problem.解决问题。

But I don't understand why.但我不明白为什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM