java 事件分发线程_深入浅出Java多线程(2)-Swing中的EDT(事件分发线程) [转载]...

本系列文章导航

本文主要解决的问题是:

如何使其Swing程序只能运行一个实例?

抛开Swing, 我们的程序是通过java 命令行启动一个进程来执行的,该问题也就是说要保证这个进程的唯一性,当然如果能够访问系统的接口,得到进程的信息来判断是否已有进程正在运行,不就解决 了吗?但是如何访问系统的接口呢?如何要保证在不同的平台上都是OK的呢?我的思路是用文件锁,当然我相信肯定有更好的方法,呵呵,希望读者能够指出。

文件锁是JDK1.4 NIO提出的,可以在读取一个文件时,获得文件锁,这个锁应该是系统维护的,JVM应该是调用的系统文件锁机制,例子如下:

packageconcurrentstudy;importjava.io.FileNotFoundException;importjava.io.IOException;importjava.io.RandomAccessFile;importjava.nio.channels.FileChannel;importjava.nio.channels.FileLock;/***@authorvma*/

public classtemp1 {public static void main(String args[]) throwsFileNotFoundException, InterruptedException, IOException {

RandomAccessFile r= new RandomAccessFile("d://testData.java", "rw");

FileChannel temp=r.getChannel();

FileLock fl=temp.lock();

System.out.println(fl.isValid());

Thread.sleep(100000);

temp.close();

}

}

当代码获得锁后:我们试图编辑这个文件是就会:

1.JPG

如果在启动一个Java Main方法时:

packageconcurrentstudy;importjava.io.FileNotFoundException;importjava.io.IOException;importjava.io.RandomAccessFile;importjava.nio.channels.FileChannel;importjava.nio.channels.FileLock;public classTemp2 {public static void main(String args[]) throwsFileNotFoundException, InterruptedException, IOException {

RandomAccessFile r= new RandomAccessFile("d://testData.java", "rw");

FileChannel temp=r.getChannel();

FileLock fl=temp.tryLock();

System.out.println(fl== null);

temp.close();

}

}

返回的结果是 ture , 也就是得不到文件的锁。

这就是对于进程唯一性问题我的解决思路,通过锁定文件使其再启动时得不到锁文件而无法启动。

说到这里,跟今天Swing中的EDT好像还没有关系,对于Swing程序,Main方法中一般像这样:

public static voidmain(String[] args) {try{

UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());

}catch(Exception e) {

}//Create the top-level container and add contents to it.

JFrame frame = new JFrame("SwingApplication");

SwingApplication app= newSwingApplication();

Component contents=app.createComponents();

frame.getContentPane().add(contents, BorderLayout.CENTER);

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.pack();

frame.setVisible(true);

启动Jframe后,Main线程就退出了,上面获得文件锁,并持有锁的逻辑往哪里写呢? 有人会说事件分发线程EDT,真的吗?

由于我没有做过Swing的项目,仅仅做过个人用的财务管理小软件,还没有深入理解过EDT,不管怎么说先把那段逻辑加到EDT,

怎么加呢 用SwingUtilities

static void invokeAndWait(Runnable doRun)

Causes doRun.run() to be executed synchronously on the AWT event dispatching thread.

static void invokeLater(Runnable doRun)

Causes doRun.run() to be executed asynchronously on the AWT event dispatching thread.

加上去以后怎么界面没有任何反应了呢?

代码如下:

packageconcurrentstudy;importjava.awt.BorderLayout;importjava.awt.Component;importjava.awt.GridLayout;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjava.awt.event.KeyEvent;importjava.io.FileNotFoundException;importjava.io.IOException;importjava.io.RandomAccessFile;importjava.lang.reflect.InvocationTargetException;importjava.nio.channels.FileChannel;importjava.nio.channels.FileLock;importjava.util.logging.Level;importjava.util.logging.Logger;importjavax.swing.BorderFactory;importjavax.swing.JButton;importjavax.swing.JFrame;importjavax.swing.JLabel;importjavax.swing.JPanel;importjavax.swing.SwingUtilities;importjavax.swing.UIManager;public classSwingApplication {private static String labelPrefix = "Number of button clicks: ";private int numClicks = 0;publicComponent createComponents() {final JLabel label = new JLabel(labelPrefix + "0");

JButton button= new JButton("I'm a Swing button!");

button.setMnemonic(KeyEvent.VK_I);

button.addActionListener(newActionListener() {public voidactionPerformed(ActionEvent e) {

numClicks++;

label.setText(labelPrefix+numClicks);

}

});

label.setLabelFor(button);/** An easy way to put space between a top-level container and its

* contents is to put the contents in a JPanel that has an "empty"

* border.*/JPanel pane= newJPanel();

pane.setBorder(BorderFactory.createEmptyBorder(30, //top

30, //left

10, //bottom

30) //right

);

pane.setLayout(new GridLayout(0, 1));

pane.add(button);

pane.add(label);returnpane;

}public static void main(String[] args) throwsInterruptedException {try{

UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());

}catch(Exception e) {

}//Create the top-level container and add contents to it.

JFrame frame = new JFrame("SwingApplication");

SwingApplication app= newSwingApplication();

Component contents=app.createComponents();

frame.getContentPane().add(contents, BorderLayout.CENTER);

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.pack();

frame.setVisible(true);try{

SwingUtilities.invokeAndWait(newgetFileLock());

}catch(InvocationTargetException ex) {

ex.printStackTrace();

}

}

}class getFileLock implementsRunnable {public voidrun() {try{

RandomAccessFile r= null;try{

r= new RandomAccessFile("d://testData.java", "rw");

}catch(FileNotFoundException ex) {

ex.printStackTrace();

}

FileChannel temp=r.getChannel();

FileLock fl= null;try{

fl=temp.lock();

}catch(IOException ex) {

Logger.getLogger(getFileLock.class.getName()).log(Level.SEVERE, null, ex);

}

System.out.println(fl.isValid());try{

Thread.sleep(Integer.MAX_VALUE);

}catch(InterruptedException ex) {

ex.printStackTrace();

}

temp.close();

}catch(IOException ex) {

ex.printStackTrace();

}

}

}

打个断点看看怎么了,断点就在这里   Thread.sleep(Integer.MAX_VALUE); 看看那个线程暂停了 看图片:

2.JPG

看到了吧,我们写的那个getFileLock 是由AWT-EventQueue-0 线程执行,看右下角调用关系,

EventDispathThread 启动 Run方法, 然后pumpEvents

取事件,然后从EventQueue取到InvocationEvent 执行Dispath

Dispath调用的就是我们在getFileLock写的run() 方法, JDK代码如下:

public voiddispatch() {if(catchExceptions) {try{

runnable.run();

}catch(Throwable t) {if (t instanceofException) {

exception=(Exception) t;

}

throwable=t;

}

}else{

runnable.run();

}if (notifier != null) {synchronized(notifier) {

notifier.notifyAll();

}

}

}

runnable.run();而如何将我们写的getFileLock加入的那个EventQueue中的呢?当然是SwingUtilities.invokeAndWait(new getFileLock());

看JDK代码:

public static void invokeAndWait(Runnable runnable) throwsInterruptedException, InvocationTargetException {if(EventQueue.isDispatchThread()) {throw new Error("Cannot call invokeAndWait from the event dispatcher thread");

}classAWTInvocationLock {}

Object lock= newAWTInvocationLock();

InvocationEvent event= new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock, true);synchronized(lock) {

Toolkit.getEventQueue().postEvent(event);

lock.wait();

}

Toolkit.getEventQueue().postEvent(event);把我们写的getFileLock 塞进了EventQueue.

这下读者对EDT有个认识了吧。

1. EDT 只有一个线程, 虽然getFileLock是实现Runnable接口,它调用的时候不是star方法启动新线程,而是直接调用run方法。

2. invokeAndWait将你写的getFileLock塞到EventQueue中。

3. Swing 事件机制采用Product Consumer模式 EDT不断的取EventQueue中的事件执行(消费者)。其他线程可以将事件塞入EventQueue中,比如鼠标点击Button是,将注册在 BUttion的事件塞入EventQueue中。

所以我们将getFileLock作为事件插入进去后 EDT分发是调用Thread.sleep(Integer.MAX_VALUE)就睡觉了,无暇管塞入EventQueue的其他事件了,比如关闭窗体。

所以绝对不能将持有锁的逻辑塞到EventQueue,而应该放到外边main线程或者其他线程里面。

提到invokeAndWait,还必须说说invokelater 这两个区别在哪里呢?

invokeAndWait与invokelater区别: 看JDK代码:

public static voidinvokeLater(Runnable runnable) {

Toolkit.getEventQueue().postEvent(newInvocationEvent(Toolkit.getDefaultToolkit(), runnable));

}public static void invokeAndWait(Runnable runnable) throwsInterruptedException, InvocationTargetException {if(EventQueue.isDispatchThread()) {throw new Error("Cannot call invokeAndWait from the event dispatcher thread");

}classAWTInvocationLock {}

Object lock= newAWTInvocationLock();

InvocationEvent event= new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock, true);synchronized(lock) {

Toolkit.getEventQueue().postEvent(event);

lock.wait();

}

Throwable eventThrowable=event.getThrowable();if (eventThrowable != null) {throw newInvocationTargetException(eventThrowable);

}

}

invokelater:当在main方法中调用SwingUtils.invokelater,后,把事件塞入EventQueue就返回了,main线程不会阻塞。

invokeAndWait: 当在Main方法中调用SwingUtils.invokeAndWait 后,看代码片段:

synchronized (lock) {

Toolkit.getEventQueue().postEvent(event);

lock.wait();

}main线程获得lock 后就wait()了,直到事件分发线程调用lock对象的notify唤醒main线程,否则main 就干等着吧。

这下明白了吧!

总之,对于我们问题最简单的方法就是是main线程里,或者在其他线程里处理。

最后的解决方案是:

packageconcurrentstudy;importjava.awt.BorderLayout;importjava.awt.Component;importjava.awt.GridLayout;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjava.awt.event.KeyEvent;importjava.io.FileNotFoundException;importjava.io.IOException;importjava.io.RandomAccessFile;importjava.nio.channels.FileChannel;importjava.nio.channels.FileLock;importjavax.swing.BorderFactory;importjavax.swing.JButton;importjavax.swing.JFrame;importjavax.swing.JLabel;importjavax.swing.JPanel;importjavax.swing.UIManager;public classSwingApplication {private static String labelPrefix = "Number of button clicks: ";private int numClicks = 0;publicComponent createComponents() {final JLabel label = new JLabel(labelPrefix + "0");

JButton button= new JButton("I'm a Swing button!");

button.setMnemonic(KeyEvent.VK_I);

button.addActionListener(newActionListener() {public voidactionPerformed(ActionEvent e) {

numClicks++;

label.setText(labelPrefix+numClicks);

}

});

label.setLabelFor(button);/** An easy way to put space between a top-level container and its

* contents is to put the contents in a JPanel that has an "empty"

* border.*/JPanel pane= newJPanel();

pane.setBorder(BorderFactory.createEmptyBorder(30, //top

30, //left

10, //bottom

30) //right

);

pane.setLayout(new GridLayout(0, 1));

pane.add(button);

pane.add(label);returnpane;

}public static void main(String[] args) throwsInterruptedException {try{

UIManager.setLookAndFeel(UIManager

.getCrossPlatformLookAndFeelClassName());

}catch(Exception e) {

}

Thread t= new Thread(newgetFileLock());

t.setDaemon(true);

t.start();//Create the top-level container and add contents to it.

JFrame frame = new JFrame("SwingApplication");

SwingApplication app= newSwingApplication();

Component contents=app.createComponents();

frame.getContentPane().add(contents, BorderLayout.CENTER);

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.pack();

frame.setVisible(true);

}

}class getFileLock implementsRunnable {public voidrun() {try{

RandomAccessFile r= null;try{

r= new RandomAccessFile("d://testData.java", "rw");

}catch(FileNotFoundException ex) {

ex.printStackTrace();

}

FileChannel temp=r.getChannel();try{

FileLock fl=temp.tryLock();if (fl == null)

System.exit(1);

}catch(IOException ex) {

ex.printStackTrace();

}try{

Thread.sleep(Integer.MAX_VALUE);

}catch(InterruptedException ex) {

ex.printStackTrace();

}

temp.close();

}catch(IOException ex) {

ex.printStackTrace();

}

}

}

在Main方法里启动一个Daemon线程,持有锁,如果拿不到锁,就退出 if(fl == null) System.exit(1);

当然这只是个解决方案,如何友好给给用户提示以及锁定那个文件就要根据具体情况而定了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/409633.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java redis 分布式锁_使用Redis单实例实现分布式锁

一、前言在同一个jvm进程中时,可以使用JUC提供的一些锁来解决多个线程竞争同一个共享资源时候的线程安全问题,但是当多个不同机器上的不同jvm进程共同竞争同一个共享资源时候,juc包的锁就无能无力了,这时候就需要分布式锁了。常见…

设计一个按优先数调度算法实现处理器调度的程序_计算机中的程序都是怎么运行的,来深入了解一下吧...

在现代计算机操作系统中,总是会保持多道程序环境。一个作业被提交后,通常经过作业调度和进程调度后,才能获得处理机。有时为提高内存利用率,还会设置中程调度。那我们先来了解一下处理机调度的层次吧。高级调度,又称作…

从数据库加载程序集

有的做MSCRM2011开发的朋友会奇怪,注册的Plugin可以注册在数据库中,那么它如何去加载这个dll呢。最近正好有空,简单地实现了一下从数据库加载程序集,关键的地方是需要使用Assembly.Load方法的一个重载: Assembly.Load(…

Android 获取包名,版本信息及VersionName名称

话不多说,直接上代码,此处,主要是在版本升级的时候,使用较多。private String getAppInfo() {try {String pkName this.getPackageName();String versionName this.getPackageManager().getPackageInfo(pkName, 0).versionName;…

mysql 查看锁_SQL-mysql锁等待与死锁

一 前言本篇是MYSQL高级进阶篇内容第二篇,学习本篇的基础是知识追寻者之前发布过的文章,尤其是《MYSQL架构入门篇》重中之重;《SQL-你真的了解什么SQL么?》《SQL-小白最佳入门sql查询一》《SQL-小白最佳入门sql查询二》《SQL- 多年…

easyui datagrid java_EasyUI DataGrid 显示不了数据????

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼Struts2:text/htmlaction:public String getList() throws Exception {// TODO Auto-generated method stubLong count (long) recruitBiz.countRecruitInfo();List list recruitBiz.findRecruitBySearch(page,rows, null);JSONO…

sed 手册阅读笔记转

原文链接sed 手册阅读笔记摘要sed 手册本身不太适合初学者,我在看的过程中加了一些 自己的注释和一些例子,帮助理解,如有偏差或错误,请指出,多谢。目录1. sed的工作原理 2. sed中如何选择特定的行 3. sed的命令行选项 …

java -cp 引用多个包_Java -cp 命令行引用多个jar包的简单写法(Windows、Linux)

1、Windows下用法在Windows上,可以使用java your-jar-lib-fold/* your-main-classyour-jar-lib-fold为存放一堆jar文件的路径。your-main-class为要运行的具有main方法的主类。JDK 1.7及以上版本支持该写法。2、Linux下用法在Linux上,这样写似乎并不支持…

python bytearray转为byte_Python3 bytearray() 函数详解 将参数转为可变的字节数组

Python3 bytearray() 函数详解 将参数转为可变的字节数组bytearray()函数的主要用途是将参数转换为一个新的字节数组&#xff0c;它是一个可变的整数序列&#xff0c;它的取值范围是0 < x < 256(0~255)&#xff0c;它具有可变序列的大多数方法。它是Python的内置函数&…

第三方库添加记录

1 ASIHTTPRequest&#xff1a; a.下载asihttprequest b.  把Classes里的文件&#xff0c;拖到XCode中  External/Reachbility也拖进去 ->这是Apple 官方用来检查网络链接是否正常的类库 c.导入框架  SystemConfiguration.framework  MobileCoreServices.framewo…

python数据标准类型_Python的标准数据类型(下)

Python的标准数据类型(下)上一篇我们讲述了 Number String List 。这一篇我们将继续学习Python的标准数据类型 。 循序渐进&#xff0c;逐渐深化。1TupleTuple(元组)Tuple 元组与列表类似不过元组的元素不能修改元组写在小括号里 ()元素之间用逗号隔开元组的元素类型也可…

mysql connetor_python mysqlconnetor

python mysqlconnetor的使用1.[代码][Python]代码# !/usr/bin python#--*-- coding:utf-8 --*--import mysql.connectorimport osimport codecs#设置数据库用户名和密码user;#用户名pwd;#密码host;#ip地址db;#所要操作数据库名字charsetUTF-8cnx mysql.connector.connect(user…

(转)HBase二级索引与Join

二级索引与索引Join是Online业务系统要求存储引擎提供的基本特性。RDBMS支持得比较好&#xff0c;NOSQL阵营也在摸索着符合自身特点的最佳解决方案。 这篇文章会以HBase做为对象来探讨如何基于Hbase构建二级索引与实现索引join。文末同时会列出目前已知的包括0.19.3版secondary…

python编程基础题答案_大学moocPython编程基础题目及答案

情境领导理论中提到的成熟度包括()A&#xff0e;生理成熟度B&#xff0e;心理成熟度C&#xff0e;年龄成熟度D&#xff0e;工作成熟度E&#xff0e;技能成要显示当前过程中的所有变量及对象的取值&#xff0c;可以利用 ______ 窗口。A&#xff0e;监视B&#xff0e;调用堆栈C&a…

mysql主要的收获_MySQL性能测试大总结

以下的文章主要是介绍MySQL性能测试的结论&#xff0c;我们大家都知道MySQL数据库在实际实用度主要是取决于MySQL数据库的性能&#xff0c;以下的文章主要就是对MySQL性能测试的一个总结&#xff0c;望你看完之后会有所收获。好像是zdnet的实验室做得一个权威测试吧sqlserver在…