Java:实现一个新线程,现在我的代码执行了两次

标签 java multithreading observer-pattern

前几天我问了另一个关于在 swing GUI 中获取键盘输入的问题——实际上是 MCR 输入。一位用户发现了某人编写的低级键盘钩子(Hook)。非常酷,而且它大部分都有效。我必须学习一些新东西来实现它(总是乐于这样做),而且我可能不完全理解发生了什么。

事情是这样的,我将在下面发布代码,当我为键盘钩子(Hook)实现线程时,它现在会通过一个 while 循环(在 CardRead.java 中成功 == false)运行两次。如果我对样本数据进行硬编码,它只会运行一次。如果我删除键盘 Hook 并使用普通的 Scanner.nextLine()(这意味着我必须在控制台中单击以向应用程序提供输入),它只会运行一次。开始一个新的线程与键盘输入的观察者?两次。我不明白为什么,或者如何解决它。只要能准确了解发生了什么,我就会很高兴——如果你们中有人能告诉我如何修复它,我会欣喜若狂。

代码如下:

CardRead.java

public class CardRead {

public static String raw_card_data;

int readcount = 1;

String[] tracks = new String[2];
String[] tracks_final = new String[2];

public static void main() 
{
    // This doesn't happen until after card is swiped, dunno why.
    //GUI.outputArea.setText(GUI.outputArea.getText() + "\n\n Scan card \n");

    boolean success = false;

    while (success == false)
    {
        //raw_card_data = "%test?;testing?"; // <-- using this, runs thru once

        // using THIS, runs through twice.
        // create an event source - reads from stdin
        final KB_EventSource evSrc = new KB_EventSource();

        // create an observer
        final KB_RespHandler respHandler = new KB_RespHandler();

        // subscribe the observer to the event source
        evSrc.addObserver( respHandler );

        // starts the event thread
        Thread kb_thread = new Thread(evSrc);
        kb_thread.start();

        // sleep until card swiped
        while (raw_card_data == null)
        {
            try
            {
                Thread.sleep(1000);

            }
            catch (Exception e)
            {
                System.out.println(e.getMessage());
            }
        }
        System.out.println(raw_card_data);

                // Tokenize raw_card_data
        StringTokenizer tokenizer = new StringTokenizer(raw_card_data, "?");
        int i = 0;
        do
        {
            tracks[i] = tokenizer.nextToken();
            System.out.println(i + ": " + tracks[i]);
            i++;
        }
        while (tokenizer.hasMoreTokens());
        //System.out.println(track1);
        //System.out.println(track2);
        tracks_final[0] = tracks[0].substring(1,tracks[0].length());
        if (tracks[1] != null)
        {
            tracks_final[1] = tracks[1].substring(1,tracks[1].length());
        }   
        if ( (readcount <= 5) && ( (tracks_final[0].equals("E") || tracks_final[0].equals(null) ) || (tracks_final[1].equals("E") || tracks_final[1].equals(null)) ) )
        {
            GUI.notout.setText("Card Read Unsuccessful. Scan Again.");
            GUI.outputArea.setText(GUI.outputArea.getText() + "Card read unsuccessful. Scan again. \n");
            success = false;
            readcount++;
        }
        else if (readcount <= 5)
        {
            GUI.notout.setText("Card Successfully Read");
            GUI.outputArea.setText(GUI.outputArea.getText() + "\n Success! \n");
            GUI.outputArea.setText(GUI.outputArea.getText() + "Track 1 = " + tracks_final[0] + "\n");
            GUI.outputArea.setText(GUI.outputArea.getText() + "Track 2 = " + tracks_final[1] + "\n");
            success = true;
        } // end if else chain
       } // end while success == false
} // end public void main
} // end class CardRead

KB_RespHandler.java

import java.util.Observable;
import java.util.Observer;

public class KB_RespHandler implements Observer 
{
private String resp;
    public void update (Observable obj, Object arg)
    {
        if (arg instanceof String) 
        {
            resp = (String) arg;
            CardRead.raw_card_data = resp;           
        }
    }
}

KB_EventSource.java

import de.ksquared.system.keyboard.*;
import java.util.Observable; 

public class KB_EventSource extends Observable implements Runnable
{
public static String temp = "";
public static String output = "";

public void run() 
{   

    new GlobalKeyListener().addKeyListener(new KeyAdapter() 
    {
        @Override public void keyPressed(KeyEvent event)
        { 
            switch(event.getVirtualKeyCode())
            {
            case KeyEvent.VK_0:
                if (event.isShiftPressed() == true)
                    temp += ")";
                else if (event.isShiftPressed() == false)
                    temp += "0";
                break;
            case KeyEvent.VK_1:
                if (event.isShiftPressed() == true)
                    temp += "!";
                else if (event.isShiftPressed() == false)
                    temp += "1";
                break;
            /*insert processing for other keys here*/
            case KeyEvent.VK_SPACE:
                if (event.isShiftPressed() == true)
                    temp += " ";
                else if (event.isShiftPressed() == false)
                    temp += " ";
                break;
            case KeyEvent.VK_RETURN:
                /*if (event.isShiftPressed() == true)
                    temp += "\n";
                else if (event.isShiftPressed() == false)
                    temp += "\n";*/
                setChanged();
                notifyObservers(temp);
                //clearChanged();
                  break;                                                                        
            } // end switch (event.getVirtualKeyCode())*/
        } // end public void keyPressed
    });
    while(true)
    try 
    { 
        Thread.sleep(100); 
    }
    catch(InterruptedException e) 
    { 
        e.printStackTrace(); 
    }
}
} 

所以,我不知道发生了什么。我在想也许我需要在收到输入后停止线程 kb_thread,但我找不到任何方法来做到这一点。 thread.stop()thread.destroy() 已弃用,Eclipse 和 Google 告诉我不要使用它们。无论如何,这甚至可能不是我需要做的。

最佳答案

“CardRead.java”中的注释说“成功后将更改 success = true”。

这是否意味着它可能会失败,所以它不会改变成功

如果这是真的,那么 raw_card_data 仍将是非空的,并且它会重试。

我假设您在某个时候再次将 raw_card_data 重置为 null。

另外一点,这个:

if (event.isShiftPressed() == true)
    temp += ")";
else if (event.isShiftPressed() == false)
    temp += "0";

可以简化为:

if (event.isShiftPressed())
    temp += ")";
else
    temp += "0";

关于Java:实现一个新线程,现在我的代码执行了两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8932740/

相关文章:

java - 身份验证 Spring SOAP 到 Workday

java - 当应用程序服务器失去互联网连接时维持服务的机制

java - 在 log4j2 配置中使用 BasicContextSelector

java - 我应该使用Hadoop吗?

c# - 使用单个巨大任务(例如 SQL 查询)杀死/中止线程

python - Django/Flask 实现 : Listen permanently to connection via HTTP or Socket.(在后台)

java - 我可以同时使用 .equal() 比较两个或多个事物吗

java - 为什么我的线程程序只使用一个 CPU?

iphone - 添加 bool 值的观察者

javascript - 无法使用订阅 Angular 结果