关于同步锁 锁住多线程启动的JFrame的问题

xdzcz 2015-03-21 05:22:42

我现在有一个父窗口,弹出子窗口让用户输入信息。想让父窗口等待子窗口的信息。
子窗口是一个extends JFrame并且implements Runnable的类,单实例模式返回一个实例创建新的Thread线程并启动。
public void actionPerformed(ActionEvent ae){
switch(ae.getActionCommand().charAt(0)){
case '1':
tablenameUI getTablename =tablenameUI.getTablenameUI();
Thread getTablenameThread = new Thread(getTablename);
getTablenameThread.start();
System.out.println("get table的UI线程启动了。");


synchronized (getTablename){
try {
System.out.println("我要wait了哦!");
getTablename.wait();
System.out.println("Oops,被唤醒了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}



这个是我单击下拉菜单下的某个actionPerformed里的同步锁的代码。


btnOk = new JButton("ok");
btnOk.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
tablename = textField.getText();
if (tablename == "")
JOptionPane.showMessageDialog(getContentPane(),"Please enter the name!");
else{
commandFrame.tablename = tablename;
System.out.println("There's something written in the textfield");

synchronized (this){
if (tablename != "**"){
notifyAll();
System.out.println("I have unlocked the lock.");

}
}

}
}
});



这个是在子窗口里用户点击OK button以后的ActionListener里的操作,一旦单击ok,则解锁。


public void run() {
System.out.println("启动run method");
setVisible(true);
}

这个是子窗口的run()方法,简单的setVisible()。


但是现在的问题是,运行的顺序都对,程序到wait时候交出同步锁,给子程序,但是子程序界面一直为空。也就是说,子程序没有输入框,也没有任何文字之类的,用户根本没办法进行操作。但是奇怪的是,这个程序的标题还是有的,“Table Name”,如下所示:



command为父窗口,table name为子窗口。子窗口里本来应该要有TextField之类的来让用户输入的,可是却没显示出来。

去掉synchronized块之后,则可以显示。也怀疑过是线程执行的顺序问题,看过大神的文章http://blog.csdn.net/nmyangym/article/details/7850882关于wait()和notify()机制,可是看测试结果来讲,顺序没问题。但是为什么子窗口无法显示?



子窗口全部代码如下:

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;

import java.awt.Font;
import java.awt.Toolkit;

import javax.swing.JTextField;
import javax.swing.JButton;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;


public class tablenameUI extends JFrame implements Runnable{

commandUI commandFrame = commandUI.getCommandUI();
static tablenameUI tablenameFrame= null;

public String tablename = "**";
private JLabel lblNewLabel;
private JLabel lblTheTable;
private JTextField textField;
private JButton btnOk;
private JButton btnCancle;

public static tablenameUI getTablenameUI(){
if (tablenameFrame == null)
tablenameFrame = new tablenameUI();
return tablenameFrame;
}



private tablenameUI() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setTitle("Table Name");
setLocation((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth()/3,
(int)Toolkit.getDefaultToolkit().getScreenSize().getHeight()/4);
setSize(410 , 300);
getContentPane().setLayout(null);

lblNewLabel = new JLabel("Please enter the name of");
lblNewLabel.setFont(new Font("Comic Sans MS", Font.PLAIN, 25));
lblNewLabel.setBounds(42, 28, 310, 61);
getContentPane().add(lblNewLabel);
System.out.println("加载了一个“姓名”标签");

lblTheTable = new JLabel("the table:");
lblTheTable.setFont(new Font("Comic Sans MS", Font.PLAIN, 25));
lblTheTable.setBounds(42, 92, 130, 61);
getContentPane().add(lblTheTable);
System.out.println("加载了一个“the table”标签");

textField = new JTextField();
textField.setFont(new Font("Comic Sans MS", Font.PLAIN, 30));
textField.setBounds(191, 102, 130, 40);
getContentPane().add(textField);
textField.setColumns(10);
System.out.println("加载了一个“textField”");

btnOk = new JButton("ok");
btnOk.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
tablename = textField.getText();
if (tablename == "")
JOptionPane.showMessageDialog(getContentPane(),"Please enter the name!");
else{
commandFrame.tablename = tablename;
System.out.println("There's something written in the textfield");

synchronized (this){
if (tablename != "**"){
notifyAll();
System.out.println("I have unlocked the lock.");

}
}

}
}
});
btnOk.setFont(new Font("Comic Sans MS", Font.PLAIN, 18));
btnOk.setBounds(49, 178, 112, 44);
getContentPane().add(btnOk);
System.out.println("加载了一个“ok”buttuon");

btnCancle = new JButton("cancel");
btnCancle.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
textField.setText("");
}
});
btnCancle.setFont(new Font("Comic Sans MS", Font.PLAIN, 18));
btnCancle.setBounds(229, 178, 112, 44);
getContentPane().add(btnCancle);
System.out.println("加载了一个“cancel”button");

//while closing this frame, set the main frame into visible
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
super.windowClosing(e);
commandUI.getCommandUI().setVisible(true);
}
});
System.out.println("全部加载完毕!");
}


@Override
public void run() {
System.out.println("启动run method");
setVisible(true);

}
}




测试后的全部显示结果如下:
加载了一个“姓名”标签
加载了一个“the table”标签
加载了一个“textField”
加载了一个“ok”buttuon
加载了一个“cancel”button
全部加载完毕!
get table的UI线程启动了。
我要wait了哦!
启动run method


然后就没有然后了……
...全文
285 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
三仙半 2015-04-10
  • 打赏
  • 举报
回复
不会吧?干嘛要都写在这个方法里面?你可以把要进行的操作分成几个方法,在这个方法里面调用,甚至,可以专门写一个类,来处理这些操作,然后,在这个方法里实例化一个对象,调用相应的方法,你说是不是这样?
xdzcz 2015-04-07
  • 打赏
  • 举报
回复
引用 4 楼 zys59 的回复:
弹出窗口后,主窗口中弹出窗口的那个方法退出,主窗口就没有其他动作了。 输入窗口关闭时会调用主窗口的方法main.setTableName(tf.getText());,在setTableName()中去继续做读数据库、绘制表格等工作。
可是这样的话,我接下来所有的命令都要写在这一个函数里,会不会太麻烦了? 我想知道为什么我的同步锁无法运行呢?
三仙半 2015-04-02
  • 打赏
  • 举报
回复
弹出窗口后,主窗口中弹出窗口的那个方法退出,主窗口就没有其他动作了。 输入窗口关闭时会调用主窗口的方法main.setTableName(tf.getText());,在setTableName()中去继续做读数据库、绘制表格等工作。
三仙半 2015-03-21
  • 打赏
  • 举报
回复

package modelWindow;

import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class MainFrame extends JFrame {
	private String strTableName;	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new MainFrame().setVisible(true);
	}	
	public MainFrame(){
		this.setSize(400,300);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setLayout(null);
		
		JButton btn = new JButton("输入表名");
		btn.setSize(100, 30);
		btn.setLocation(10, 10);
		this.add(btn);
		btn.addActionListener(new ActionListener() {			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				MainFrame.this.setEnabled(false);
				new InputFrame(MainFrame.this).setVisible(true);
			}
		});
	}
	public void setTableName(String tablename){
		this.setEnabled(true);
		strTableName = tablename;
		System.out.println("用户输入的表名是:"+strTableName);
	}
}

class InputFrame extends JFrame implements WindowListener{
	//父窗口的引用
	private MainFrame main;
	private TextField tf = new TextField();
	public InputFrame(MainFrame main){
		//输入窗口显示状态设置
		this.main = main;
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setSize(215, 120);
		this.setResizable(false);
		this.setLayout(null);
		//输入框
		tf.setEditable(true);
		tf.setLocation(10, 10);
		tf.setSize(186, 35);
		this.add(tf);
		//确定按钮
		JButton btn = new JButton("确认输入");
		btn.setSize(100, 30);
		btn.setLocation(50, 55);
		this.add(btn);
		btn.addActionListener(new ActionListener() {			
			@Override
			public void actionPerformed(ActionEvent e) {
				if(!tf.getText().equals("")){
					InputFrame.this.dispose();
				}
			}
		});
		//监听窗口事件
		this.addWindowListener(this);
	}
	@Override
	public void windowClosed(WindowEvent e) {
		//将输入传回父窗口
		main.setTableName(tf.getText());
	}
	@Override
	public void windowClosing(WindowEvent e) {
	}
	@Override
	public void windowOpened(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void windowIconified(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void windowDeiconified(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void windowActivated(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void windowDeactivated(WindowEvent e) {
		// TODO Auto-generated method stub
		
	}
}
三仙半 2015-03-21
  • 打赏
  • 举报
回复
这个子窗口就是要接收输入吗?没有必要使用线程吧? 直接弹出一个模态窗口,接受输入,处理关闭事件,将用户输入传回父窗口,ok了。
xdzcz 2015-03-21
  • 打赏
  • 举报
回复
引用 1 楼 zys59 的回复:
这个子窗口就是要接收输入吗?没有必要使用线程吧? 直接弹出一个模态窗口,接受输入,处理关闭事件,将用户输入传回父窗口,ok了。
引用 1 楼 zys59 的回复:
这个子窗口就是要接收输入吗?没有必要使用线程吧? 直接弹出一个模态窗口,接受输入,处理关闭事件,将用户输入传回父窗口,ok了。
看了您的代码,涨了不少知识!! 可是我这里是想要等待窗口返回值,我在主窗口内还有一些绘制表格之类的操作,想要等待子窗口返回表名以后,去数据库里搜索表格,然后绘制在主窗口上。所以必须让主窗口的线程阻塞吧?模态有办法等待子窗口吗?

58,454

社区成员

发帖
与我相关
我的任务
社区描述
Java Eclipse
社区管理员
  • Eclipse
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧