我目前正在学习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();
}
}
答案 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(原子和易失性)或同步,但我并不认为这是问题所在。