同步问题

时间:2015-01-24 17:02:22

标签: java synchronize

基本上,我需要暂停我的程序而我正在等待主JFrame中的JTextField的输入,以及所有其他元素,因此它不是弹出窗口。但是,我正在这样做的方式它暂停整个程序,因为我正在使用while(true)或类似的东西。

以下是我的GUI的外观,以便您更好地了解我在说什么;

img

当我输入命令start并按回车键时,您可以看到程序卡住了。


这是我初始化同步的方式:

    input = new JTextField();
    inputScrollPane = new JScrollPane(input, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    input.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            if (waitingForInput) {
                synchronized (holder) {
                    holder.add(input.getText());
                    holder.notify();
                }
                waitingForInput = false;
            }

            JTextField sauce = (JTextField) e.getSource();
            appendCommand(sauce.getText());
            sauce.setText("");
        }
    });

以下是我在LinkedStack上调用notify时会发生什么......

public String getInput(String s) {
    appendInput(s + ": ");
    input.requestFocus();

    synchronized (holder) {
        while (holder.isEmpty())
            //System.out.println("input inside 2"); //STOPS HERE
            try {
                holder.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        System.out.println("input inside 3");

        String nextString = holder.remove(0);

        System.out.println(nextString);
        return nextString;
    }

    /*Document document = getConsoleInput().getDocument();
    Element rootElem = document.getDefaultRootElement();
    int numLines = rootElem.getElementCount();
    Element lineElem = rootElem.getElement(numLines - 2);
    int lineStart = lineElem.getStartOffset();
    int lineEnd = lineElem.getEndOffset();
    try {
        System.out.println(document.getText(lineStart, lineEnd - lineStart));
        return document.getText(lineStart, lineEnd - lineStart);
    } catch (BadLocationException e) {
        e.printStackTrace();
        return "-1";
    } */           //another attempt I had
}

这是按顺序调用的方法的层次结构或链:

我初始化JTextField的开始:

input = new JTextField();
    inputScrollPane = new JScrollPane(input, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    input.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            if (waitingForInput) {

                synchronized (holder) {
                    holder.add(input.getText());
                    holder.notify();
                }
                waitingForInput = false;
            }

            JTextField sauce = (JTextField) e.getSource();
            appendCommand(sauce.getText()); //<<<
            sauce.setText("");
        }
    });

在EDT内部调用的AppendCommand(String s)方法

public void appendCommand(String s) {
    appendInput(s);
    if (!testIfValid(s)) return;
    handler = new CommandHandler(getCurrentInstance());
    switch (CommandList.valueOf(s.toUpperCase())) {
        case HELP:
            handler.help();
            break;
        case START:
            handler.start(currentLevelActive);  //<<<<<<<<<<<
            break;
        case STOP:

            break;
        case EXIT:

            break;
        //default:

    }
}

下一个:

  public void start(Level l) {
    level_instance = l;
    if (level_instance != null) {
        level_instance.start();
    } else {
        //CREATE new level
        int width = 0, height = 0;
        boolean go;

        console_instance.waitingForInput(true);
        console_instance.setInputMessage("Enter level width : ");
        InputThread widthThread = new InputThread("width", console_instance);

        while (!widthThread.done) {
        } ///STOPS HERE ETERNALY!!
        width = widthThread.getInputResult();

        ...

InputThread类:

class InputThread extends Thread {
Console console_instance;
String choice;
int inputResult;
boolean done;

public InputThread(String s, Console c) {
    console_instance = c;
    choice = s;
}

@Override
public void run() {
    String s = "";
    console_instance.setWaitingForInput(true);
    do {
        s = console_instance.getInput("Enter " + choice + " of the level"); // <<<<<<<<<<
    } while (!isInt(s));
    inputResult = Integer.parseInt(s);
    done = true;
}

public int getInputResult() {
    return inputResult;
}

private boolean isInt(String s) {
    int i;
    boolean b;
    try {
        i = Integer.parseInt(s);
        b = true;
        if (i < 0) {
            b = false;
        }
    } catch (NumberFormatException ne) {
        b = false;
    }
    return b;
}
}

Console.getInput(String s)方法:

public String getInput(String s) {
    appendInput(s + ": ");
    input.requestFocus();

    synchronized (holder) {
        while (holder.isEmpty())
            //System.out.println("input inside 2"); //STOPS HERE
            try {
                holder.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        System.out.println("input inside 3");

        String nextString = holder.remove(0);

        System.out.println(nextString);
        return nextString;
    }
}

以及它在那个循环中停止的位置。然而,这也会停止整个计划。

对于可能的解决方案,我试图隔离Threads中的部分代码,但无济于事......如果你可以帮我修改这段代码以使其正常运行或给我另一种方法来实现这一目标,那就太好了。


编辑:正如@markspace所建议的那样,我试图实现SwingWorker,首先是在EDT线程中,由于UI仍然挂起,然后在getInput(String s)方法中,它不起作用。对于后者,这就是代码的样子:

public String getInput(String s) {
    waitingForInput = true;
    appendInput(s + ": ");
    input.requestFocus();
    String result = "";
    synchronized (holder) {

        worker = new SwingWorker<String, String>() {
            @Override
            public String doInBackground() {
                while (holder.isEmpty()) {
                    //System.out.println("input inside 2"); //STOPS HERE
                    try {
                        holder.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                return holder.remove(0);
            }

            @Override
            public void done() {
                String s ="";
                try {
                    s = super.get();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
                System.out.println(s);

            }
        };

        while(!worker.isDone()) {}
        try {
            result = worker.get().toString();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(result);
        return result;

    }

1 个答案:

答案 0 :(得分:0)

我设法通过将原始Map包装在另一个Map内来解决问题,该put(...)在调用包装好的地图CommandHandler时调用方法。这将它传递给我的另一个班级{{1}},并从那里开始自我解释。