我有一个扩展JDialog的登录表单,用户可以通过刷卡或通过输入用户名和密码进行登录。从事件派发线程(EventQueue)停止另一个线程
我创建了一个Runnable
守护进程,它与磁条阅读器进行通信,当它启动时,它将请求刷卡并等待,直到刷卡。如果应用程序需要取消请求以执行其他操作,那么它将产生该线程将捕获的事件,从而取消等待刷卡的请求。
当用户刷卡时,应用程序将读取用户ID的轨迹并验证它,如果验证成功,停止命令将被发送到卡刷卡守护进程并停止线程。
当用户输入用户名和密码时,swing程序包将访问响应登录按钮的单击事件的线程(AWT-EventQueue-0)并继续评估登录凭证。
我的问题是,每当应用程序在这个AWT-EventQueue-0线程上,向卡刷卡守护进程发送停止事件将不起作用,守护进程将停留在线程堆栈上。
编辑1:停止命令在刷卡登录时工作得很好。它优雅地结束了刷卡线程。在这种情况下,当前线程作用域位于CardSwipeThread上。
问题发生在手动登录时,当用户单击登录按钮时,当前有效范围的线程将是AWT-EventQueue-0或Event Dispatch Thread。将CardSwipeThread的volatile布尔值更新为false不会阻止其运行。
编辑2:读卡器与应用程序通信的唯一时间是刷卡时,手动登录时发生问题,不需要刷卡。因此,CardSwipeThread没有问题,因为IO操作被阻止而无法正常结束。原来,有一个隐藏在灌木丛后面。
这是我的代码的一部分:
LoginDialog.java
public class LoginDialog extends JDialog implements ActionListener, WindowListener
{
public LoginDialog()
{
super();
// ..More code that instantiates the objects of this JDialog.
SwipeReader.getInstance().enable(true);
}
class SymAction implements java.awt.event.ActionListener
{
public void actionPerformed(java.awt.event.ActionEvent event)
{
Object object = event.getSource();
if (object == logonButton)
{
logonButton_actionPerformed(event);
}
// ..More conditions for other objects.
}
}
// The keyboard login method, does not terminate the card swipe daemon thread.
void logonButton_actionPerformed(java.awt.event.ActionEvent event)
{
try
{
// ..More code that will evaluate login information.
if (authenticate == -1)
{
// Notify for failed login.
}
else if (authenticate == 0)
{
SwipeReader.getInstance().enable(false);
}
}
catch (Exception e)
{
// Error logger.
}
}
// The card swipe listener used for card login.
public void deviceDataReceived(Object object)
{
try
{
// ..More code that will evaluate login information.
if (authenticate == -1)
{
// Notify for failed login.
}
if (authenticate == 0)
{
SwipeReader.getInstance().enable(false);
}
}
catch (Exception e)
{
// Error logger.
}
}
}
SwipeReader.java
public class SwipeReader
{
// This is a singleton class that creates the thread for the daemon.
CardSwipeDaemon cardSwipeDaemon;
Thread cardSwipeThread;
SwipeReader instance;
private SwipeReader() {}
public static SwipeReader getInstance()
{
if (instance == null) { instance = new SwipeReader(); }
return instance;
}
public void enable (boolean isEnabled)
{
if (isEnabled)
{
cardSwipeDaemon = new CardSwipeDaemon();
cardSwipeThread = new Thread(cardSwipeDaemon, "CardSwipeThread");
cardSwipeThread.start();
}
else
{
cardSwipeDaemon.stop();
cardSwipeThread = null;
}
}
}
CardSwipeDaemon.java
public class CardSwipeDaemon implements Runnable
{
CardSwipeDaemon instance;
private static volatile boolean listenforswipe = true;
public CardSwipeDaemon() {}
public static synchronized CardSwipeDaemon getInstance()
{
if (instance == null) { instance = new CardSwipeDaemon(); }
return instance;
}
public run()
{
listenforswipe = true;
while (listenforswipe)
{
// Code for reading the magnetic stripe data.
}
}
public void stop()
{
listenforswipe = false;
}
}
一次只能运行CardSwipeReader的一个实例,SwipeReader.java的目的是创建CardSwipeReader的新实例(如果它为null或仅返回存在的实例)。我没有包含读取磁条数据的代码,因为我认为它与我的问题无关,而且我只需要关闭CardSwipeThread。我需要停止CardSwipeThread,因为读者不仅可以用于登录,还可以进一步将信用付款用于应用程序。我在我的问题中添加了更多信息。 – ELM
@ELM **显然,您在CardSwipeReader中阻止了IO,导致无法完成** –
@ELM:读卡器API可能允许规定超时,以减轻此风险。 – trashgod