我有一个扩展 JDialog 的登录表单,用户可以通过刷卡或输入用户名和密码登录。
我创建了一个Runnable
与磁条阅读器通信的守护程序,启动时它将请求刷卡,它会等到刷卡。如果应用程序需要取消请求以执行其他操作,那么它将产生该线程将捕获的事件,从而取消等待刷卡的请求。
当用户刷卡时,应用程序将读取用户ID的轨迹并进行验证,如果验证成功,将向刷卡守护进程发送停止命令并停止线程。
当用户输入用户名和密码时,swing 包将访问一个线程 (AWT-EventQueue-0),该线程响应登录按钮的单击事件并继续评估登录凭据。
我的问题是,每当应用程序在此 AWT-EventQueue-0 线程上时,向刷卡守护程序发送停止事件将不起作用,并且该守护程序将保留在线程堆栈上。
编辑1:停止命令在刷卡登录时工作得很好。它优雅地结束了刷卡线程。在这种情况下,当前线程范围在 CardSwipeThread 上。
问题发生在手动登录时,当用户单击登录按钮时,当前作用域线程将是 AWT-EventQueue-0 或事件调度线程。将 CardSwipeThread 的 volatile 布尔值更新为 false 并不会阻止它运行。
编辑2: 读卡器与应用程序通信的唯一时间是刷卡时,问题发生在不需要刷卡的手动登录上。因此,不会因为阻塞的 IO 操作而导致 CardSwipeThread 没有正确结束的问题。原来有一个躲在灌木丛后面。
这是我的代码的一部分:
登录对话框.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;
}
}