为什么在Java中打印所有正在运行的线程会解除应用程序的阻塞?
我在JavaFX中创建了一个GUI应用程序,该应用程序与串行设备通信(我使用一个。当我想要获取数据时,我发送一个通信,然后等待1s,直到等待函数终止。当我单击其中一个按钮(用于启动设备、用于识别等)时,也会发送通信。在开发过程中,我注意到一个错误——当我点击太多按钮或点击发送多个通信的按钮时,通信挂起(但只有在收到消息时,我仍然可以发送单向通信,例如启动设备) 通信主要由我自己的类SerialPortDevice处理。我创建一个类类型的对象,然后调用特定的方法。下面是等待消息的方法:为什么在Java中打印所有正在运行的线程会解除应用程序的阻塞?,java,multithreading,javafx,Java,Multithreading,Javafx,我在JavaFX中创建了一个GUI应用程序,该应用程序与串行设备通信(我使用一个。当我想要获取数据时,我发送一个通信,然后等待1s,直到等待函数终止。当我单击其中一个按钮(用于启动设备、用于识别等)时,也会发送通信。在开发过程中,我注意到一个错误——当我点击太多按钮或点击发送多个通信的按钮时,通信挂起(但只有在收到消息时,我仍然可以发送单向通信,例如启动设备) 通信主要由我自己的类SerialPortDevice处理。我创建一个类类型的对象,然后调用特定的方法。下面是等待消息的方法: priva
private String waitForMessage() throws SerialPortException {
long operationStartTime = System.currentTimeMillis();
long connectionTimeout = SerialPortCommunicationParameters.CONNECTION_TIMEOUT_IN_MILLIS;
String resultMessage = "";
do {
if (readEventOccurred) {
System.out.println();
resultMessage = receiveMessage();
System.out.println("After receiving a message");
messageReceived = true;
}
} while (((System.currentTimeMillis() - operationStartTime) < connectionTimeout) && (!messageReceived));
if (!readEventOccurred) {
resultMessage = NO_RESPONSE;
}
System.out.println("Time elapsed: " + (System.currentTimeMillis() - operationStartTime + "ms"));
return resultMessage;
}
ReadEventOccursed是SerialPortDevice类中的一个布尔字段,其中包含WaitFormMessage函数。另外,WaitFormMessage由另一个函数调用,singleConversation:
String singleConversation(String testMessage) {
String resultMessage = NO_RESPONSE;
try {
openConnection();
sendMessage(testMessage);
resultMessage = waitForMessage();
closeConnection();
} catch (SerialPortException e) {
e.printStackTrace();
return resultMessage;
}
System.out.println();
readEventOccurred = false;
messageReceived = false;
return resultMessage;
}
。。。这是将ReadEventOccursed设置为false的唯一函数。它是串行端口设备类中的一个“顶级”函数,处理发送和接收与设备的通信。因此,通信是这样的:
按钮单击->按钮处理程序调用->设备。singleCommunication(特定于按钮的\u Communication)->一些方法运行,然后到达WaitFormMessage->方法等待事件发生1s->事件发生(每次-我得到“串行事件发生”通信)->ReadEventOccursed设置为true->如果还有时间的话(总有一些时间剩余,一切都会持续一毫秒),消息是通过WaitFormMessage方法接收的 如果我单击延迟较短的按钮(比如2-3秒),或者我没有单击这些按钮,那么就没有问题了。在不同的情况下,会发生奇怪的事情。我仍然会收到消息“Serial Event Occursed”(因此我认为ReadEventOccursed也被设置为true)但WaitFormMessage函数不执行
if(readEventOccured)
语句的代码。此外,我必须再次运行应用程序才能与设备通信(我的意思是接收数据,发送工作正常)
解决我问题的方法是在ReadEventOccursed标志中添加“volatile”修饰符(顺便说一句,事情有时进展得很快)。但我并不满意。我想让代码在没有“volatile”的情况下正确运行.我的同事想出了一个主意,当我点击按钮并调用通信时,正在创建的线程出现了问题-可能有什么东西在某处阻止了其他事情?我做的第一件事是打印所有当前运行的线程,然后…伙计,它解决了一个问题。应用程序不再挂起。真的,我执行了“挂起”场景10-20次,带和不带
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
System.out.println(threadSet);
Set threadSet=Thread.getAllStackTraces().keySet();
系统输出打印LN(螺纹组);
在WaitFormMessage方法的开始,结果是明确的——它以某种方式解决了我的问题。我几乎可以肯定的是,获取和打印线程本身并不是一个解决方案。这是一个正在进行的过程,但我不知道这是什么。有什么有用的信息吗?也许更好地理解Java中的线程会对我有所帮助?或者是其他什么 干杯 解决我问题的方法是在ReadEventOccursed标志中添加“volatile”修饰符(顺便说一句,事情有时进展得很快)。但我并不满意。我想让代码在没有“volatile”的情况下正确运行 添加volatile修复了这个问题,这表明当涉及多个线程时,Java内存模型缺乏保证。简单地说,除了特定情况外,无法保证一个线程上的更改在其他线程上是可见的 打印“修复”问题的原因可能是:
boolean flag = false;
void consume() {
while (true) {
if (flag) {
//we received flag, hooray
}
}
}
void produce() {
flag = true;
}
现在,如果product()
和consume()
在不同的线程中运行,则绝对不能保证consume()
将看到标志设置为true。volatile
创建内存b
boolean flag = false;
void consume() {
while (true) {
if (flag) {
//we received flag, hooray
}
}
}
void produce() {
flag = true;
}