简体   繁体   English

使用侦听器的怪异Java并发问题

[英]Weird java concurrency issue using a listener

I'm currently learning concurrency in java and I just wondered if java listeners would be thread safe, so I wrote this up. 我目前正在学习Java的并发性,我只是想知道Java侦听器是否是线程安全的,所以我写了这个。 I've come across a really odd issue where if println is commented out, the program will never exit. 我遇到了一个非常奇怪的问题,即如果将println注释掉,该程序将永远不会退出。 Am i not making something synchronized when i should? 我应该在什么时候不同步一些东西吗?

Any ideas? 有任何想法吗?

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class MainComponent implements MainThreadListener
{
    private static final int THREADS = 10;
    int notifsOld;
    int notifs;

    public MainComponent()
    {
        notifs = 0;
        notifsOld=0;
    }

    public void start()
    {
        dispatch();
        loop();
    }
    public void dispatch()
    {
        /*  start 10 threads
         *  the lewThread starts, sleeps for (0-10 secs)
         *  and then notifies the MainComponents implemented listener */

          for (int i = 0; i <= THREADS; i++) {
            new LewThread(this).start();
        }
    }

    public void loop()
    {
        while(notifs < THREADS)
        {
            /* when println is commented out, the program will never end. ??? */
            //System.out.println(notifs);
            if(notifs != notifsOld)
            {
                /* this only runs once at the end */
                notifsOld = notifs;
                System.out.println("notifs changed");
            }
        }
    }

    @Override
    public void threadNotified(){notifs++;}

    public static void main(String... args)
    {
        new MainComponent().start();
    }

}

Just try to synchronize you threadNotified method : 只需尝试同步您的threadNotified方法:

public synchronized void threadNotified(){notifs++;}

this will ensure no 2 threads will increment notifs at the same time, which would result in a single increment. 这将确保没有2个线程将同时增加notifs ,这将导致一个增量。 You should probably also synchronize all access to the variables. 您可能还应该同步所有对变量的访问。

I think a simpler alternative would be mark the notifs variable as volatile : 我认为一个更简单的选择是将notifs变量标记为volatile:

volatile int notifsOld;
volatile int notifs;

Usually, in java, each thread gets its own local copy of each variables. 通常,在Java中,每个线程都会获得每个变量自己的本地副本。 Volatile ensures that all those copies are synchronized before being red or written. 易失性确保所有这些副本在被红色或写入之前都已同步。 So all threads act on the same values of the variables. 因此,所有线程都作用于变量的相同值。

It looks like you have run into the classic "Performance Testing" issue of JIT languages. 看来您已经遇到了经典的JIT语言“性能测试”问题。 JIT (Just In Time) compilers will only compile code paths which have an observable output. JIT(Just In Time)编译器将仅编译具有可观察输出的代码路径。 When you comment out the Println, the code no longer does anything, so the compiler optimises the entire code branch away. 当您注释掉Println时,代码不再执行任何操作,因此编译器会优化整个代码分支。

Most likely the entire code branch loop() is optimised away, and only dispatch runs. 最有可能优化了整个代码分支loop(),并且仅运行调度。 You can try using eclipses "step over" command in debug to see if it actually runs loop. 您可以尝试在调试中使用eclipses“ step over”命令来查看它是否真正运行循环。 Alternatively, try putting "println(notifs + " " + notifsOld") after loop(); 或者,尝试将“ println(notifs +”“ + notifsOld”)放在loop()之后; this should make the notifs updates important again. 这将使通知更新再次变得重要。

Also, you should make Notifs (atomic and volatile) or synchronized, but I don't really think that is the problem here. 另外,您应该使Notifs(原子的和易失的)或同步,但是我并不真正认为这是问题所在。

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

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