14 多线程,gui
多线程:
并行与并发:
并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要多核CPU)
并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安排轮流进行,由于时间
间隔较短,使人感觉两个任务都在运行。
JVM的启动是多线程的吗?
JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。
多线程程序实现的方式1:
继承Thread
* 定义类继承Thread
* 重写run方法
* 把新线程要做的事写在run方法中
* 创建线程对象
* 开启新线程, 内部会自动执行run方法
多线程程序实现的方式2:
实现Runnable
* 定义类实现Runnable接口
* 实现run方法
* 把新线程要做的事写在run方法中
* 创建自定义的Runnable的子类对象
* 创建Thread对象, 传入Runnable
* 调用start()开启新线程, 内部会自动调用Runnable的run()方法
public class Demo1_Thread { public static void main(String[] args) { // 多线程程序实现 // new MyThread().start(); new Thread(new MyRunnable()).start(); for (int i = 0; i < 1000; i++) { System.out.println("bbbbbbbbbbbb"); } } } class MyThread extends Thread{ // 方式1 public void run() { for (int i = 0; i < 1000; i++) { System.out.println("aaaaaaaaaaaaa"); } } } class MyRunnable implements Runnable{ // 方式2 @Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println("aaaaaaaaaaaaa"); } } }
实现Runnable的原理
Thread类的构造函数,传递了Runnable接口的引用
通过init()方法找到传递的target给成员变量的target赋值
查看run方法,发现run方法中有判断,如果target不为null就会调用Runnable接口子类对象
的run方法
两种方式的区别:
继承Thread : 由于子类重写了Thread类的run(), 当调用start()时, 直接找子类的run()方法
实现Runnable : 构造函数中传入了Runnable的引用, 成员变量记住了它, start()调用run()
方法时内部判断成员变量Runnable的引用是否为空, 不为空编译时看的是Runnable的run(),运行时执行
的是子类的run()方法
继承Thread
好处:可以直接使用Thread类中的方法,代码简单
弊端:如果已经有了父类,就不能用这种方法
实现Runnable接口:
好处:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是
可以多实现的
弊端:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码
复杂
匿名内部类实现线程的两种方式:
public class Demo2_Thread { public static void main(String[] args) { // 匿名内部类实现线程的两种方式 new Thread() { public void run() { for (int i = 0; i < 1000; i++) { System.out.println("aaaa"); } } }.start(); new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println("bbbb"); } } }).start(); } }
获取名字和设置名字:
* 1.获取名字
* 通过getName()方法获取线程对象的名字 //this.getName()
* 2.设置名字
* 通过构造函数可以传入String类型的名字 //new Thread("xxx")
* 通过setName(String)方法可以设置线程对象的名字 //t1.setName("xxx")// this.setName
("xxx")
获取当前线程的对象:
* Thread.currentThread(), 主线程也可以获取
休眠线程:
* Thread.sleep(毫秒,纳秒)
守护线程setDaemon:
public class Demo3_Daemon { public static void main(String[] args) { //setDaemon(), 设置一个线程为守护线程, //该线程不会单独执行, 当其他非守护线程都执行结束后, 自动退出 Thread t1 = new Thread() { public void run() { for (int i = 0; i < 2; i++) { System.out.println(getName ()+"aaaaaaaaaaaaaaaaaaaa"); } } }; Thread t2 = new Thread() { public void run() { for (int i = 0; i < 20; i++) { System.out.println(getName()+"bbb"); } } }; t2.setDaemon(true); //t1结束,t2会随之结束 t1.start(); t2.start(); } }
join:
public class Demo4_Join { public static void main(String[] args) { //join(), 当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续 // join(int), 可以等待指定的毫秒之后继续 final Thread t1 = new Thread() { public void run() { for (int i = 0; i <10; i++) { System.out.println(getName ()+"aaaaaaaaaaaaaaaaaaaa"); } } }; Thread t2 = new Thread() { public void run() { for (int i = 0; i < 20; i++) { if (i==2) { try { t1.join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(getName()+"bbb"); } } }; t1.start(); t2.start(); } }
yield:
public class Demo5_Yield { public static void main(String[] args) { // yield让出cpu new MyThead().start(); new MyThead().start(); } } class MyThead extends Thread{ public void run() { for (int i = 0; i <1000; i++) { if (i%10==0) { Thread.yield(); } System.out.println(getName()+i); } } }
setPriority()设置线程的优先级 1~10
同步:
public class Demo6_synchronized { /*//同步 当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切 换到其他线程工作. 这时就需要同步. 如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码. 同步代码块 使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块 多个同步代码块如果使用相同的锁对象, 那么他们就是同步的*/ public static void main(String[] args) { Object lock = new Object(); ////锁对象可以是任意对象,需要保证是同一把锁,不 能用匿名对象 Printer printer = new Printer(); synchronized (lock) { new Thread() { public void run() { for (int i = 0; i < 100; i++) { printer.print1(); } } }.start(); } synchronized (lock) { new Thread() { public void run() { for (int i = 0; i < 100; i++) { printer.print2(); } } }.start(); } } } class Printer{ public static void print1() { System.out.println("1"); System.out.println("2"); System.out.println("3"); System.out.println("4"); System.out.println("\r\n"); } public static void print2() { System.out.println("A"); System.out.println("B"); System.out.println("C"); System.out.println("D"); System.out.println("\r\n"); } }
同步方法:
public class Demo7_synchronized { //使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的 public static void main(String[] args) { // Printer1 printer = new Printer1(); Printer2 printer = new Printer2(); new Thread() { public void run() { for (int i = 0; i < 100; i++) { printer.print1(); } } }.start(); new Thread() { public void run() { for (int i = 0; i < 100; i++) { printer.print2(); } } }.start(); } } class Printer1{ // 静态的同步函数的锁是:字节码对象 public synchronized static void print1() { System.out.println("1"); System.out.println("2"); System.out.println("3"); System.out.println("4"); System.out.println("\r\n"); } public static void print2() { synchronized (Printer1.class) { System.out.println("A"); System.out.println("B"); System.out.println("C"); System.out.println("D"); System.out.println("\r\n"); } } } class Printer2{ // 非静态同步函数的锁是:this public synchronized void print1() { System.out.println("1"); System.out.println("2"); System.out.println("3"); System.out.println("4"); System.out.println("\r\n"); } public void print2() { synchronized (this) { System.out.println("A"); System.out.println("B"); System.out.println("C"); System.out.println("D"); System.out.println("\r\n"); } } }
线程安全问题:
public class Test1 { public static void main(String[] args) { //多线程并发操作同一数据时, 就有可能出现线程安全问题 //使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起 操作 // new Ticket().start(); // new Ticket().start(); // new Ticket().start(); // new Ticket().start(); Ticket2 ticket2 = new Ticket2(); new Thread(ticket2).start(); new Thread(ticket2).start(); new Thread(ticket2).start(); new Thread(ticket2).start(); } } class Ticket extends Thread{ private static int ticket = 100; // private static Object object = new Object(); public void run() { while(true) { synchronized (Ticket.class) { if (ticket<=0) { break; } try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + ":这是第" + ticket-- + "张 票"); } } } } class Ticket2 implements Runnable{ private static int ticket = 100; @Override public void run() { // TODO Auto-generated method stub while(true) { synchronized (this) { if (ticket<=0) { break; } try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":这 是第" + ticket-- + "张票"); } } } }
多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁
尽量不要嵌套使用
synchronized(s1) {
System.out.println(getName());
synchronized(s2) {
System.out.println(getName());
}
}
Vector,StringBuffer,Hashtable
Collections.synchroinzed(xxx)可以变成安全
* Vector是线程安全的,ArrayList是线程不安全的
* StringBuffer是线程安全的,StringBuilder是线程不安全的
* Hashtable是线程安全的,HashMap是线程不安全的
单例设计模式:
public class Demo1_Singleton { public static void main(String[] args) { // 单例设计模式:保证类在内存中只有一个对象 Singleton s1 = Singleton.getIntance(); Singleton s2 = Singleton.getIntance(); System.out.println(s1==s2); //true } } //饿汉式,空间换时间 class Singleton{ private Singleton(){} private static Singleton s = new Singleton(); public static Singleton getIntance() { return s; } } //懒汉式,单例的延时加载模式,存在多线程的问题,时间换空间 class Singleton1{ private Singleton1(){} private static Singleton1 s; public static Singleton1 getIntance() { if (s==null) { s = new Singleton1(); } return s; } } //final修饰 class Singleton2 { private Singleton2() {} public static final Singleton2 s = new Singleton2();//final修饰的变量不可以被更改 }
Runtime类是一个单例类
Runtime r = Runtime.getRuntime();
//r.exec("shutdown -s -t 300"); //300秒后关机
r.exec("shutdown -a");
Timer:
import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class Demo2_Timer { public static void main(String[] args) throws Throwable { //Timer类:计时器 Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("执行任务"); } }, new Date(),3000); while(true) { Thread.sleep(1000); System.out.println(new Date()); } } }
两个线程间的通信:
public class Demo3_Notify { public static void main(String[] args) { //等待唤醒机制 // 如果希望线程等待, 就调用wait() // 如果希望唤醒等待的线程, 就调用notify(); // 这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用 /*ABCD 1234 ABCD 1234*/ Printer printer = new Printer(); new Thread() { public void run() { while(true) { try { printer.print1(); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while(true) { try { printer.print2(); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } } class Printer{ private int flag = 1; public void print1() throws InterruptedException { synchronized (this) { if (flag!=1) { this.wait(); } System.out.print("A"); System.out.print("B"); System.out.print("C"); System.out.print("D"); System.out.print("\r\n"); flag = 2; this.notify(); } } public void print2() throws InterruptedException { synchronized (this) { if (flag!=2) { this.wait(); } System.out.print("1"); System.out.print("2"); System.out.print("3"); System.out.print("4"); System.out.print("\r\n"); flag = 1; this.notify(); } } }
多个线程通信:
public class Demo4_notifyall { public static void main(String[] args) { /*多个线程通信的问题 * notify()方法是随机唤醒一个线程 * notifyAll()方法是唤醒所有线程 * JDK5之前无法唤醒指定的一个线程 * 如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来反复判断 条件*/ Printers printer = new Printers(); new Thread() { public void run() { while(true) { try { printer.print1(); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while(true) { try { printer.print2(); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while(true) { try { printer.print3(); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } } class Printers{ private int flag = 1; public void print1() throws InterruptedException { synchronized (this) { while (flag!=1) { //if语句是在哪里等待,就在哪里起来 //while循环是循环判断,每次都会判断标记 this.wait(); } System.out.print("A"); System.out.print("B"); System.out.print("C"); System.out.print("D"); System.out.print("\r\n"); flag = 2; this.notifyAll(); } } public void print2() throws InterruptedException { synchronized (this) { while (flag!=2) { this.wait(); } System.out.print("1"); System.out.print("2"); System.out.print("3"); System.out.print("4"); System.out.print("\r\n"); flag = 3; this.notifyAll(); } } public void print3() throws InterruptedException { synchronized (this) { while (flag!=3) { this.wait(); } System.out.print("a"); System.out.print("b"); System.out.print("c"); System.out.print("d"); System.out.print("\r\n"); flag = 1; this.notifyAll(); } } }
在同步代码块中,用哪个对象锁,就用哪个对象调用wait方法
为什么wait方法和notify方法定义在Object这类中?
因为锁对象可以是任意对象,Object是所有的类的基类,所以wait方法和notify方法需要定义在
Object这个类中
sleep方法和wait方法的区别?
* sleep方法必须传入参数,参数就是时间,时间到了自动醒来wait方法可以传入参数也可以不传入参数,
传入参数就是在参数的时间结束后等待,不传入参数就是直接等待
* sleep方法在同步函数或同步代码块中,不释放锁,睡着了也抱着锁睡,wait方法在同步函数或者同步
代码块中,释放锁
ReentrantLock类:
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Demo5_ReentrantLock { public static void main(String[] args) { /*JDK1.5的新特性互斥锁 同步 * 使用ReentrantLock类的lock()和unlock()方法进行同步 通信 * 使用ReentrantLock类的newCondition()方法可以获取Condition对象 * 需要等待的时候使用Condition的await()方法, 唤醒的时候用signal()方法 * 不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了*/ Printers1 printer = new Printers1(); new Thread() { public void run() { while(true) { try { printer.print1(); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while(true) { try { printer.print2(); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); new Thread() { public void run() { while(true) { try { printer.print3(); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } } class Printers1{ private int flag = 1; private ReentrantLock r = new ReentrantLock(); private Condition c1 = r.newCondition(); private Condition c2 = r.newCondition(); private Condition c3 = r.newCondition(); public void print1() throws InterruptedException { r.lock(); if (flag!=1) { c1.await(); } System.out.print("A"); System.out.print("B"); System.out.print("C"); System.out.print("D"); System.out.print("\r\n"); flag = 2; c2.signal(); r.unlock(); } public void print2() throws InterruptedException { r.lock(); if (flag!=2) { c2.await(); } System.out.print("1"); System.out.print("2"); System.out.print("3"); System.out.print("4"); System.out.print("\r\n"); flag = 3; c3.signal(); r.unlock(); } public void print3() throws InterruptedException { r.lock(); if (flag!=3) { c3.await(); } System.out.print("a"); System.out.print("b"); System.out.print("c"); System.out.print("d"); System.out.print("\r\n"); flag = 1; c1.signal(); r.unlock(); } }
线程组:
public class Demo6_ThreadGroup { public static void main(String[] args) { /*Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许 程序直接对线程组进行控制。 * 默认情况下,所有的线程都属于主线程组。 * public final ThreadGroup getThreadGroup()//通过线程对象获取他所属 于的组 * public final String getName()//通过线程组对象获取他组的名字 * 可以给线程设置分组 * 1,ThreadGroup(String name) 创建线程组对象并给其赋值名字 * 2,创建线程对象 * 3,Thread(ThreadGroup?group, Runnable?target, String?name) * 4,设置整组的优先级或者守护线程*/ MyRunnable1 mr = new MyRunnable1(); Thread t1 = new Thread(mr); Thread t2 = new Thread(mr); //线程组的使用,默认是主线程组 System.out.println(t1.getThreadGroup().getName()); //main System.out.println(t2.getThreadGroup().getName()); //main // 自己设定线程组 ThreadGroup threadGroup = new ThreadGroup("自己设定线程组"); MyRunnable1 mr2 = new MyRunnable1(); System.out.println(new Thread(threadGroup, mr2).getThreadGroup().getName ()); //自己设定线程组 System.out.println(new Thread(threadGroup, mr2).getThreadGroup().getName ()); //自己设定线程组 } } class MyRunnable1 implements Runnable{ @Override public void run() { // TODO Auto-generated method stub } }
线程池概述
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可
以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。线程池
里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使
用。在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池
内置线程池的使用概述
JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
* public static ExecutorService newFixedThreadPool(int nThreads)
* public static ExecutorService newSingleThreadExecutor()
* 这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行
Runnable对象或者Callable对象代表的线程。它提供了如下方法
* Future<?> submit(Runnable task)
* <T> Future<T> submit(Callable<T> task)
* 使用步骤:
* 创建线程池对象
* 创建Runnable实例
* 提交Runnable实例
* 关闭线程池
*
* 提交的是Runnable
*
ExecutorService pool = Executors.newFixedThreadPool(2);
// 可以执行Runnable对象或者Callable对象代表的线程
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
//结束线程池
pool.shutdown();
多线程程序实现的方式3(了解)
* 提交的是Callable
* 好处:
* 可以有返回值
* 可以抛出异常
* 弊端:
* 代码比较复杂,所以一般不用
*
// 创建线程池对象 ExecutorService pool = Executors.newFixedThreadPool(2); // 可以执行Runnable对象或者Callable对象代表的线程 Future<Integer> f1 = pool.submit(new MyCallable(100)); Future<Integer> f2 = pool.submit(new MyCallable(200)); // V get() Integer i1 = f1.get(); Integer i2 = f2.get(); System.out.println(i1); System.out.println(i2); // 结束 pool.shutdown(); public class MyCallable implements Callable<Integer> { private int number; public MyCallable(int number) { this.number = number; } @Override public Integer call() throws Exception { int sum = 0; for (int x = 1; x <= number; x++) { sum += x; } return sum; } }
简单工厂模式概述和使用
简单工厂模式概述
又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例
客户端不需要在负责对象的创建,从而明确了各个类的职责
这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不
断的修改工厂类,不利于后期的维护
示例:
* 动物抽象类:public abstract Animal { public abstract void eat(); }
* 具体狗类:public class Dog extends Animal {}
* 具体猫类:public class Cat extends Animal {}
* 开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比较麻烦,就
需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。
public class AnimalFactory { private AnimalFactory(){} //public static Dog createDog() {return new Dog();} //public static Cat createCat() {return new Cat();} //改进 public static Animal createAnimal(String animalName) { if(“dog”.equals(animalName)) {return new Dog();} else if(“cat”.equals(animale)) { return new Cat(); }else { return null; } } }
工厂方法模式概述:
工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实
现。
* 客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个
具体的类和具体的工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性
* 需要额外的编写代码,增加了工作量
* 示例
*
动物抽象类:public abstract Animal { public abstract void eat(); }
工厂接口:public interface Factory {public abstract Animal createAnimal();}
具体狗类:public class Dog extends Animal {}
具体猫类:public class Cat extends Animal {}
开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比较麻
烦,就需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。发现每次修改代码太麻烦,
用工厂方法改进,针对每一个具体的实现提供一个具体工厂。
狗工厂:public class DogFactory implements Factory {
public Animal createAnimal() {…}
}
猫工厂:public class CatFactory implements Factory {
public Animal createAnimal() {…}
}
GUI:
Frame f = new Frame(“my window”);
f.setLayout(new FlowLayout());//设置布局管理器
f.setSize(500,400);//设置窗体大小
f.setLocation(300,200);//设置窗体出现在屏幕的位置
Button button = new Button("按钮1");
f.add(button);
f.setIconImage(Toolkit.getDefaultToolkit().createImage("qq.png"));//设置图
标,默认是咖啡
f.setVisible(true);
布局管理器:
* FlowLayout(流式布局管理器)
* 从左到右的顺序排列。
* Panel默认的布局管理器。
* BorderLayout(边界布局管理器)
* 东,南,西,北,中
* Frame默认的布局管理器。
* GridLayout(网格布局管理器)
* 规则的矩阵
* CardLayout(卡片布局管理器)
* 选项卡
* GridBagLayout(网格包布局管理器)
* 非规则的矩阵
import java.awt.Button; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; public class Demo1_Frame { public static void main(String[] args) { Frame frame = new Frame("my window"); frame.setLayout(new FlowLayout());;//设置窗体大小 frame.setSize(500,400);//设置窗体大小 frame.setLocation(300,200);//设置窗体出现在屏幕的位置 frame.setIconImage(Toolkit.getDefaultToolkit().createImage("qq.png"));//设 置图标,默认是咖啡 Button button = new Button("按钮1"); Button button1 = new Button("按钮2"); frame.add(button); frame.add(button1); button.addMouseListener(new MouseAdapter() { /*@Override public void mouseClicked(MouseEvent e) { //点击 System.exit(0); }*/ @Override public void mouseReleased(MouseEvent e) { //释放 System.exit(0); } }); button.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { System.out.println(e.getKeyCode()); // if (e.getKeyCode()==32) { //空格 if (e.getKeyCode()==KeyEvent.VK_SPACE) { //空格 System.exit(0); } } }); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); //动作监听 button1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.exit(0); } }); frame.setVisible(true); } }
事件处理
* 事件: 用户的一个操作
* 事件源: 被操作的组件
* 监听器: 一个自定义类的对象, 实现了监听器接口, 包含事件处理方法,把监听器添加在事件
源上, 当事件发生的时候虚拟机就会自动调用监听器中的事件处理方法
适配器设计模式:
* .什么是适配器
* 在使用监听器的时候, 需要定义一个类事件监听器接口.
* 通常接口中有多个方法, 而程序中不一定所有的都用到, 但又必须重写, 这很繁琐.
* 适配器简化了这些操作, 我们定义监听器时只要继承适配器, 然后重写需要的方法即可.
* .适配器原理
* 适配器就是一个类, 实现了监听器接口, 所有抽象方法都重写了, 但是方法全是空的.
* 适配器类需要定义成抽象的,因为创建该类对象,调用空方法是没有意义的
* 目的就是为了简化程序员的操作, 定义监听器时继承适配器, 只重写需要的方法就可以了.
public class test1 { // 适配器设计模式 } interface Inter{ public void A(); public void B(); public void C(); public void D(); } abstract class InterAdapter implements Inter{ @Override public void A() { } @Override public void B() { } @Override public void C() { } @Override public void D() { } } class MyInter extends InterAdapter{ @Override public void A() { } }
总结:
1、单例设计模式,适配器设计模式
单例设计模式:
在java中,单例模式是指为了保证类在内存中只有一个对象,而形成的一种固有的代
码模式
适配器设计模式:
在java中,适配器设计模式是指为了监视某些行为,但是对于每种监听到的行为又有
不同的处理,为了能够让监听者自行来处理监听到指定行为后,要做的后续操作,而形成的一种固有的
代码模式
* a.什么是适配器
* 在使用监听器的时候, 需要定义一个类事件监听器接口.
* 通常接口中有多个方法, 而程序中不一定所有的都用到, 但又必须重写,
这很繁琐.
* 适配器简化了这些操作, 我们定义监听器时只要继承适配器, 然后重写需
要的方法即可.
* b.适配器原理
* 适配器就是一个类, 实现了监听器接口, 所有抽象方法都重写了, 但是方
法全是空的.
* 适配器类需要定义成抽象的,因为创建该类对象,调用空方法是没有意义的
* 目的就是为了简化程序员的操作, 定义监听器时继承适配器, 只重写需要
的方法就可以了.
2、饿汉式和懒汉式的区别
使用场合:
饿汉式: 开发用
懒汉式: 面使用,开发一般不用
思想:
饿汉式: 类一加载就生成对象。
懒汉式: 在调用获取对象的方法的时候生成。
实用性:
饿汉式: 安全,效率高。相对懒汉式会在未使用之前就占用内存。
懒汉式: 存在线程安全漏洞,可以利用同步解决,但是效率会变低。内存方面符合了
编程中的延迟加载思想。(在面试中面试官会比较希望答出这一点)
3、Timer类
Timer类是计时器。
一般的使用过程是在Timer类的schedule()方法中传入两个参数,一个TimerTask的子类对象,
在这个子类对象中规定了计时结束的操作,另一个java.util.Date类的对象,其参数指定了计时的开始时
间和循环周期,
4、wait和sleep的区别
sleep方法:定义在Thread类中,让线程在指定时间内处于休眠状态,超时后继续向下执行,休
眠的线程不会释放锁资源。
wait方法 :定义在Object类中,让以当前对象为监视器的线程处于阻塞状态,不可获取执行权
,在得到notify或者notifyAll的通知后再继续抢夺执行权。等待的线程会释放锁资源。
5、线程的生命周期(五中状态的切换流程)
线程分为5个生命周期,新建,就绪,运行,阻塞,死亡
其中:
新建代表线程在内存中创建,对应start方法。
就绪代表线程拥有抢夺执行权的资格,如果抢到就会执行线程中的内容
运行代码线程中的内容正在执行。
a:若被抢走执行权,回到就绪状态
b:若执行ssleep、wait等方法,会进入阻塞状态。
阻塞代表线程被强制不可进入就绪状态,对于非就绪状态的线程是没有机会抢夺执行
权,也就更不可能进入运行状态了。
死亡代表线程运行结束,也可能是被强制结束,一般不建议使用。

浙公网安备 33010602011771号