JDialog を拡張するログイン フォームがあります。ユーザーは、カードをスワイプするか、ユーザー名とパスワードを入力してログインできます。
磁気ストライプ リーダーと通信するデーモンを作成しましたRunnable
。起動すると、カードのスワイプが要求され、カードがスワイプされるまで待機します。アプリケーションが何か他のことをするためにリクエストをキャンセルする必要がある場合、このスレッドがキャッチするイベントを生成し、カード スワイプを待つリクエストをキャンセルします。
ユーザーがカードをスワイプすると、アプリケーションはユーザー ID のトラックを読み取って検証します。認証が成功すると、停止コマンドがカード スワイプ デーモンに送信され、スレッドが停止します。
ユーザーがユーザー名とパスワードを入力すると、swing パッケージはログイン ボタンのクリック イベントに応答するスレッド (AWT-EventQueue-0) にアクセスし、ログイン資格情報の評価に進みます。
私の問題は、アプリケーションがこの AWT-EventQueue-0 スレッド上にあるときはいつでも、停止イベントをカード スワイプ デーモンに送信しても機能せず、デーモンがスレッド スタックに留まることです。
編集 1:停止コマンドは、カード スワイプ ログインで完全に正常に機能します。カードスワイプスレッドを正常に終了します。このシナリオでは、現在のスレッド スコープは CardSwipeThread にあります。
この問題は手動ログインで発生します。ユーザーがログイン ボタンをクリックすると、現在のスコープ スレッドは AWT-EventQueue-0 またはイベント ディスパッチ スレッドになります。CardSwipeThread の volatile ブール値を false に更新しても、実行は停止しません。
編集 2: リーダーがアプリケーションと通信するのは、カードがスワイプされたときだけであり、スワイプを必要としない手動ログインで問題が発生します。したがって、ブロックされた IO 操作が原因で CardSwipeThread が適切に終了しないという問題はありません。茂みの後ろに隠れていることがわかりました。
これは私のコードの一部です:
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;
}
}