1

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;
    }
}
4

2 に答える 2

3

SwingWorker<Boolean, Boolean>このコンテキストでの使用を検討してください。execute()ログインダイアログを表示する前に、ワーカーを呼び出します。の実装でリーダーをポーリングしdoInBackground()publish()結果が利用可能になった場合にポーリングします。イベント ディスパッチ スレッドprocess()で実行される の実装は、リーダー認証が成功した場合にダイアログを閉じることができます。は を実装しているため、キーボード ログインが成功するとワーカーを使用できます。その他の例については、 Worker Threads と SwingWorkerおよびタグを参照してください。SwingWorkerFuturecancel()

これには、コードを少し手直しする必要があります。

努力する価値はあると思いますが、積極的にリファクタリングを行う前に、いくつかの例を実行することをお勧めします。データ フローを確認するには、疑似デバイスから読み取るこの例を試してください。どのように機能するかを確認するには、任意の を実行するこのcancel()を試してください。Process

于 2017-08-23T06:37:35.490 に答える