有和没有线程的并发

时间:2012-09-03 21:42:01

标签: java concurrency derby

我有一个需要登录用户的应用程序。数据存储在Derby DB中。下面的表单根据用户名和密码字段查询它,并设置用户会话,该会话应填充用户数据。

但是,即使db正在验证用户,会话也会返回null。我怎么能把system.out.println放在这个类的main方法中,它会返回基于db查询的会话数据,而不是立即执行代码并返回null?

注意:数据库工作正常。我可以根据sql语句中的用户名和密码字段获得结果。

public class LoginForm{

    private static JTextField userName;
    private static JTextField password;
    private static JButton submit;
    private static int attempts;
    private static JFrame main;

    private Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();

    final int MAX_ATTEMPTS = 5;

    private UserSession session;

    public LoginForm(){

        Handler handle = new Handler();                             //inner class
        LoginFormFocusListener fl = new LoginFormFocusListener();   //inner class

        main = new JFrame();

        main.setUndecorated(true);
        main.setBounds((dim.width/2) - (500/2),(dim.height/2) - (150/2),500, 75);
        main.setVisible(true);
        main.setAlwaysOnTop(true);
        main.setResizable(false);
        main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        userName = new JTextField(10);
        password = new JTextField(10);
        main.setLayout(new GridLayout(0,1));

        JPanel panel = new JPanel();
        main.add(panel);

        panel.add(new JLabel("Username: "));
        panel.add(userName);
        panel.add(new JLabel("Password: "));
        panel.add(password);
        panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createBevelBorder(4), "Please Login"));

        submit = new JButton("Submit");
        panel.add(submit);

        if(attempts > 0){
            panel.add(new JLabel("" + (MAX_ATTEMPTS - attempts) + " attempts remaining..."));
        }

        main.addWindowFocusListener(fl);
        submit.addActionListener(handle);
    }



    public UserSession getSession(){
        return this.session;
    }

    /**
     * creates the session that's returned to main/POSsystem via getSession
     * @author Matt
     *
     */
    private class Handler implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e) {
            String user = userName.getText();
            String pass = password.getText();

            session = new UserSession();
            if(session.authenticate(user,  pass)){
                System.out.println("User has been authenticated");
                JOptionPane.showMessageDialog(null,"Login Successful! ","",JOptionPane.PLAIN_MESSAGE);
            }else{
                System.out.println("Login Failed!");
                JOptionPane.showMessageDialog(null,"Login Failed!","", JOptionPane.WARNING_MESSAGE);
                attempts++;
                if(attempts < MAX_ATTEMPTS){
                    new LoginForm();
                }else{
                    JOptionPane.showMessageDialog(null, "Max attempts reached.  " +
                                                        "Please Contact the administrator of this system. ",
                                                        "User Locked",
                                                        JOptionPane.ERROR_MESSAGE);
                }
            }
        }
    }

    /**
     * Inner Class
     * custom focus events for the login form
     * the user may click away from this pop-up to close it.
     * @author Matt
     *
     */
    public class LoginFormFocusListener implements WindowFocusListener{

        @Override
        public void windowGainedFocus(WindowEvent wEvt) {}

        @Override
        public void windowLostFocus(WindowEvent wEvt) {
            ((JFrame) wEvt.getSource()).dispose();
        } 
    }    

    //test
    public static void main(String args[]){

        SwingUtilities.invokeLater(new Runnable(){  
              public void run(){  
                LoginForm lf = new LoginForm();  
                System.out.println("Session: " + lf.getSession());    <---NULL!!!
              }  
            });  


    }

}

2 个答案:

答案 0 :(得分:2)

如果你真正想要的是将输出输出到控制台,那么你应该将它放在main方法中,而不是将System.out.println代码放在​​actionPerformed方法的最后一行。

如果你真的,真的,真的想在main方法中拥有该代码,那么你应该创建一个实现Runnable接口的类,它允许获取创建的LoginForm

像这样:

final class InitThread implements Runnable {
LoginForm lf;

public LoginForm getLfForSystemOut() {
    while (lf == null) {
        try {
            Thread.sleep(500);
        } catch (final InterruptedException e) {
            return null;
        }
    }
    synchronized (lf) {
        try {
            lf.wait();
            return lf;
        } catch (final InterruptedException e) {
            e.printStackTrace();
        }
    }
    return null;
}

@Override
public void run() {
    lf = new LoginForm();
}
}

然后将main方法更改为:

public static void main(final String args[]) {

    final InitThread init = new InitThread();
    SwingUtilities.invokeLater(init);

    System.out.println("Session: " + init.getLfForSystemOut().getSession());

}

最后在此块的actionPerformed方法结束时:

synchronized (LoginForm.this) {
    LoginForm.this.notifyAll();
}

答案 1 :(得分:1)

您遇到的问题是因为您在用户有机会填写表单并按“提交”按钮之前尝试获取会话。

当按下提交按钮时,将异步调用处理程序,在创建表单后将直接调用main中的println。您要么必须等到会话不再为null,要么在处理程序中使用经过身份验证的会话。