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

时间:2014-04-13 09:59:30

标签: java concurrency listener

我目前正在学习Java中的并发性,我只是想知道java监听器是否是线程安全的,所以我写了这篇文章。我遇到了一个非常奇怪的问题,如果println被注释掉,程序将永远不会退出。我不应该在我应该做同步的事情吗?

有什么想法吗?

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

}

2 个答案:

答案 0 :(得分:0)

尝试同步threadNotified方法:

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

这将确保没有2个线程同时增加notifs,这将导致单个增量。您可能还应该同步对变量的所有访问。

我认为更简单的替代方法是将notifs变量标记为volatile:

volatile int notifsOld;
volatile int notifs;

通常,在java中,每个线程都获得自己的每个变量的本地副本。易失性确保所有这些副本在被红色或写入之前同步。所以所有线程都对变量的相同值起作用。

答案 1 :(得分:0)

看起来你已经遇到了经典的&#34;性能测试&#34; JIT语言问题。 JIT(Just In Time)编译器只会编译具有可观察输出的代码路径。当您注释掉Println时,代码不再执行任何操作,因此编译器会优化整个代码分支。

最有可能整个代码分支循环()被优化掉,只运行调度。您可以尝试使用日食&#34;跳过&#34;在debug中命令查看它是否实际运行循环。或者,尝试在loop()之后放置&#34; println(notifs +&#34;&#34; + notifsOld&#34;);这应该使通知更新重要。

另外,你应该制作Notifs(原子和易失性)或同步,但我并不认为这是问题所在。