事件处理

1、事件监听机制组成:事件源(组件)、事件(Event)、监听器(Listener)、事件处理(引发事件后处理方式)。
*所有事件对象都派生于java.util.EventObject类

2、为了实现ActionListener接口,监听器必须有一个被称为actionPerformed的方法,该方法接收一个ActionEvent参数:

class MyListener implements ActionListener
 {
 ….
 public void actionPerformed(ActionEvent event)
 {
 ……
 }
 }

并发

1、进程:应用程序在内存中分配的空间(正在运行的程序)。
线程:是进程中负责程序执行的执行单元,也成为执行路径。一个进程中至少有一个线程在负责该进程的运行。如果一个进程中出现了多个线程,就称该程序为多线程程序。
多线程技术:解决多部分代码同时执行的需求,合理的使用CPU资源。
*多线程的运行根据CPU的切换完成的。怎么切换由CPU决定,所以多线程运行有一个随机性(CPU的快速切换造成的)
*JVM中的多线程:至少有两个线程,一个负责自定义代码运行,一个负责垃圾回收。
*每个线程都有运行的代码内容,称之为线程的任务。创建一个线程就是为了运行制定的任务代码。线程的任务都封装在特定的区域中,比如,主线程运行的任务都定义在main方法中,垃圾回收线程在收垃圾都会运行finalize方法。

2、多线程的安全问题
*产生原因:
(1)线程任务中有处理到共享的数据;
(2)线程任务中有多条对共享数据的操作。(一个线程在操作共享数据的过程中其他线程参与了运算,造成了数据的错误)
*解决思想:只要保证多条操作共享数据的代码在某一段时间被一条线程所执行,在执行期间不允许其他线程参与运算。方式是使用同步代码块:
Synchronized(对象)
{
需要被同步的代码
}
*同步代码块保证一次只能有一个线程执行,其他此案城进不来,这就是同步锁机制。好处是解决了多线程的安全问题,弊端是浪费资源,降低效率。

3、创建线程的两种方式(通过java.lang.Thread类)
(1)继承Thread类:
1)继承Thread类;
2)覆盖run方法;
3)创建子类对象就是创建线程对象
4)调用Thread类中的start方法就可以执行线程,并调用run方法
*start方法开启线程后都会执行run方法,说明run方法中存储的是线程要运行的代码。所以自定义线程的任务代码都存储在run方法中。
(2)实现Runnable接口(解耦:降低了线程对象和线程任务的耦合性):
1)定义一个类实现Runnable接口
2)覆盖Runnable接口中run方法,将线程要运行的代码存储到方法中
3)通过Thread类创建线程对象,并将实现了Runnable接口的对象作为Thread类的构造函数的参数进行传递
4)调用Thread类的start方法,开启线程
*实现Runnable接口的好处:
(1)避免了继承Thread类的单继承的局限性
(2)Runnable接口的出现更符合面对对象,将线程单独进行对象封装
(3)Runnable接口的出现,降低了线程对象和线程任务的耦合性
*调用start方法和run方法的区别:调用start方法会开启线程,让开启的线程去执行run方法中的线程任务;直接调用run方法,线程并未开启,去执行run方法的只有主线程。

4、使用等待唤醒机制:
(1)wait():该方法可以让线程处于冻结状态,并将线程临时存储到线程池当中;
(2)notify():唤醒指定线程池当中的任意线程;
(3)notifyAll():唤醒指定线程池中的所有线程;
*这些方法必须使用在同步中,因为它们用来操作同步锁上的状态。使用这些方法必须表示它们所属的锁,标识方式是:
锁对象.wait(); 锁对象.notify(); 锁对象.notifyAll();
相同锁的notify方法可以唤醒相同锁的wait方法。
*wait方法和sleep方法的区别
相同点:可以让线程处于冻结状态;
不同点:wait方法可以指定时间,也可以不指定;sleep方法必须指定时间;
wait方法释放CPU资源,释放锁;sleep方法释放CPU资源,不是释放锁;

5、Lock接口:解决多产生多消费的效率问题。
lock()获取锁 unlock()释放锁
*Lock接口按照面对对象的思想将锁单独封装成了一个对象,并提供显式操作。

6、线程状态

线程有六个状态:
new(新创建)
Runnable(可运行)
Blocked(被阻塞)
Waiting(等待)
Timed waiting(计时等待)
Terminated(被终止)
*一旦调用start方法,线程处于runnable状态。抢占式调度系统给每一个可运行线程一个时间片来执行任务,当时间片用完,操作系统剥夺该线程的运行权,并给另一个线程机会。
*现在所有的桌面及服务器操作系统都是要抢占式调度,手机类的小型设备使用协调式调度。
*在具有多个处理器的机器上,每一个处理器运行一个线程,可以有多个线程并行运行。当线程数目多于处理器数目时,调度器依然采取时间片机制。
*在任何给定时刻,一个可运行的线程可能正在运行也可能没有运行。
*线程终止的原因:
(1)因为run方法正常退出而正常死亡;
*线程任务通常都有循环,因为开启线程就是为了执行需要一定时间的代码。只要控制循环,就可以结束run方法,设置一个标志即可停止线程而控制循环。
(2)因为一个没有捕获的异常终止run方法而意外死亡。

7、线程属性:线程优先级、守护线程、线程组、处理未捕获异常的处理器
(1)线程优先级:调用setPriority方法提高或降低任何线程的优先级。优先级可设置在MIN_PRIORITY(在Thread类中定义为1)和MAX_PRIORITY(定义为10)之间,NORM_PRIORITY被定义为5.
(2)守护线程:调用setDaemon方法将线程转换为守护线程。当只剩下守护线程时,虚拟机退出,程序没必要继续运行。
(3)处理未捕获异常的处理器:该处理器必须实现Thread.UncaughtExceptionHandler接口的类。
(4)线程组:一个可以统一管理的线程集合。

8、有种情况:多线程出现安全问题以后,加入了同步机制,但安全问题依旧?
原因:同步除了问题,只要遵守同步的前提就可以解决。
同步的前提:多个线程在同步中必须使用同一个锁,这才是多线程同步
同步表现形式:同步代码块和同步函数
*在懒汉式单例模式中,多线程并发访问时会出现安全问题,加入同步就可以解决问题。无论是同步代码块还是同步函数,但效率会变低。可以通过if对单例对象的双重判断的形式解决效率问题。
*同步函数和同步代码块的区别:同步代码块使用任意对象作为锁,同步函数只能使用this作为锁。如果一个类只需要一个锁,这时可以考虑使用同步函数,使用this,写法简单;如果一个类中需要多个锁,或者多个类使用同一个锁,这时只能使用同步代码块,建议使用同步代码块。