关注公众号,获取更多面试题及答案。
一、java 事件机制
java 事件机制包括三个部分:事件、事件监听器、事件源。
1、事件。一般继承自 java.util.EventObject 类,封装了事件源对象及跟事件相关的信息。
com.javaedu.event.CusEvent 类
Java 代码
* 事件类,用于封装事件源及一些与事件相关的参数.
* @author Eric
*/
1. package com.javaedu.event;
2.
3. import java.util.EventObject;
4.
5. /**
6.
7.
8.
9. public class CusEvent extends EventObject {
10.
11.
12.
13.
14.
15.
16.
17.
}
private static final long serialVersionUID = 1L;
private Object source;//事件源
public CusEvent(Object source){
super(source);
this.source = source;
public Object getSource() {
return source;
}
public void setSource(Object source) {
this.source = source;
}
18.
19.
20.
21.
22.
23.
24.
25. }
2、事件监听器。实现 java.util.EventListener 接口,注册在事件源上,当事件源的属性或状态
改变时,取得相应的监听器调用其内部的回调方法。
com.javaedu.event.CusEventListener 类
Java 代码
* 事件监听器,实现 java.util.EventListener 接口。定义回调方法,将你想要做的事
* 放到这个方法下,因为事件源发生相应的事件时会调用这个方法。
* @author Eric
*/
1. package com.javaedu.event;
2.
3. import java.util.EventListener;
4.
5. /**
6.
7.
8.
9.
10. public class CusEventListener implements EventListener {
11.
12.
13.
14.
15.
16.
//事件发生后的回调方法
public void fireCusEvent(CusEvent e){
EventSourceObject eObject = (EventSourceObject)e.getSource();
System.out.println("My name has been changed!");
System.out.println("I got a new name,named \""+eObject.getName()+"\"
");
}
17. }
3、事件源。事件发生的地方,由于事件源的某项属性或状态发生了改变(比如 BUTTON 被
单击、TEXTBOX 的值发生改变等等)导致某项事件发生。换句话说就是生成了相应的事件
对象。因为事件监听器要注册在事件源上,所以事件源类中应该要有盛装监听器的容器
(List,Set 等等)。
com.javaedu.event.EventSourceObject 类
Java 代码
1. package com.javaedu.event;
private String name;
//监听器容器
private Set listener;
public EventSourceObject(){
this.listener = new HashSet();
this.name = "defaultname";
}
//给事件源注册监听器
public void addCusListener(CusEventListener cel){
}
//当事件发生时,通知注册在该事件源上的所有监听器做出相应的反应(调用回调方法)
protected void notifies(){
CusEventListener cel = null;
Iterator iterator = this.listener.iterator();
while(iterator.hasNext()){
cel = iterator.next();
cel.fireCusEvent(new CusEvent(this));
this.listener.add(cel);
* 事件源.
* @author Eric
2.
3. import java.util.HashSet;
4. import java.util.Iterator;
5. import java.util.Set;
6.
7. /**
8.
9.
10. */
11. public class EventSourceObject {
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42. }
}
public String getName() {
this.name = name;
notifies();
}
}
}
return name;
下面是主方法类
com.javaedu.event.MainTest 类、
}
//模拟事件触发器,当成员变量 name 的值发生变化时,触发事件。
public void setName(String name) {
if(!this.name.equals(name)){
Java 代码
/**
* @param args
*/
public static void main(String[] args) {
EventSourceObject object = new EventSourceObject();
//注册监听器
object.addCusListener(new CusEventListener(){
@Override
public void fireCusEvent(CusEvent e) {
super.fireCusEvent(e);
1. package com.javaedu.event;
2.
3. public class MainTest {
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20. }
}
}
});
//触发事件
object.setName("eric");
一、 Java 线程池使用说明
一简介
线程的使用在 java 中占有极其重要的地位,在 jdk1.4 极其之前的 jdk 版本中,关于线程
池的使用是极其简陋的。在 jdk1.5 之后这一情况有了很大的改观。Jdk1.5 之后加入了
java.util.concurrent 包,这个包中主要介绍 java 中线程以及线程池的使用。为我们在开发中
处理线程的问题提供了非常大的帮助。
二:线程池
线程池的作用:
线程池作用就是限制系统中执行线程的数量。
根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪
费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排队等
候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进
程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池中有等待的工
作线程,就可以开始运行了;否则进入等待队列。
为什么要用线程池:
1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内
存,而把服务器累趴下(每个线程需要大约 1MB 内存,线程开的越多,消耗的内存也就
越大,最后死机)。
Java 里面线程池的顶级接口是 Executor,但是严格意义上讲 Executor 并不是一个
线程池,而只是一个执行线程的工具。真正的线程池接口是 ExecutorService。
比较重要的几个类:
ExecutorService
ScheduledExecutorService
真正的线程池接口。
能和 Timer/TimerTask 类似,解决那些需要任务重复执行的问
题。
ThreadPoolExecutor
ScheduledThreadPoolExecutor 继承 ThreadPoolExecutor 的 ScheduledExecutorService
ExecutorService 的默认实现。
接口实现,周期性任务调度的类实现。
要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有
可能配置的线程池不是较优的,因此在 Executors 类里面提供了一些静态工厂,生成
一些常用的线程池。
1. newSingleThreadExecutor
创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程
串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代
它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
2.newFixedThreadPool
创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池
的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常
而结束,那么线程池会补充一个新线程。
3. newCachedThreadPool
创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,
那么就会回收部分空闲(60 秒不执行任务)的线程,当任务数增加时,此线程池又可
以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全
依赖于操作系统(或者说 JVM)能够创建的最大线程大小。
4.newScheduledThreadPool
创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
实例
1:newSingleThreadExecutor
MyThread.java
Public class MyThread extends Thread {
@Override
publicvoid run() {
System.out.println(Thread.currentThread().getName() + "正在执行。。。");
}
}
TestSingleThreadExecutor.java
Public class TestSingleThreadExecutor {
publicstaticvoid main(String[] args) {
//创建一个可重用固定线程数的线程池
ExecutorService pool = Executors. newSingleThreadExecutor();
//创建实现了 Runnable 接口对象,Thread 对象当然也实现了 Runnable 接口
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
Thread t4 = new MyThread();
Thread t5 = new MyThread();
//将线程放入池中进行执行
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
//关闭线程池
pool.shutdown();
}
}
输出结果
pool-1-thread-1 正在执行。。。
pool-1-thread-1 正在执行。。。
pool-1-thread-1 正在执行。。。
pool-1-thread-1 正在执行。。。
pool-1-thread-1 正在执行。。。
2newFixedThreadPool
TestFixedThreadPool.Java
publicclass TestFixedThreadPool {
publicstaticvoid main(String[] args) {
//创建一个可重用固定线程数的线程池
ExecutorService pool = Executors.newFixedThreadPool(2);
//创建实现了 Runnable 接口对象,Thread 对象当然也实现了 Runnable 接口
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
Thread t4 = new MyThread();
Thread t5 = new MyThread();
//将线程放入池中进行执行
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
//关闭线程池
pool.shutdown();
}
}
输出结果
pool-1-thread-1 正在执行。。。
pool-1-thread-2 正在执行。。。
pool-1-thread-1 正在执行。。。
pool-1-thread-2 正在执行。。。
pool-1-thread-1 正在执行。。。
3 newCachedThreadPool
TestCachedThreadPool.java
publicclass TestCachedThreadPool {
publicstaticvoid main(String[] args) {
//创建一个可重用固定线程数的线程池
ExecutorService pool = Executors.newCachedThreadPool();
//创建实现了 Runnable 接口对象,Thread 对象当然也实现了 Runnable 接口
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();