java基础复习(二十三)

多线程单例设计模式;保存类在内存中只有一个对象;

public static void main(String[] args){
    //Singleton s1 = Singleton.s;
    //Singleton.s = null;
    //Singleton s2 = Singleton.s;
    //System.out.println(s1 == s2);
    //成员变量私有,不能通过类名调用
    
    Singleton s1 = Singleton.getInstance();
     
}
//单例设计模式
//饿汉式 上来就创建对象
//饿汉式为什么好
//多线程访问
class Singleton {
    //1.私有构造方法,其他类不能使用该构造方法了
    private Singleton() {
        
    }
    //2.创建本类对象
    private static final Singleton s = new Singleton();
    //3.对外提供公共的访问方法
    public static Singleton getInstance () { //获取实例
        return s;
    }
}
//懒汉式 开发的时候不用 面试的时候用 单例的延迟加载模式
class Singleton {
    //1.私有构造方法,其他类不能访问该构造方法;
    private Singleton() {}
    //2.声明一个引用
    private static Singleton s;
    //3.对外提供公共的访问方法
    public static Singleton getInstance() {
        if (s == null){
            //线程1等待,线程2等待
            s = new Singleton();
        }
    }
}

饿汉式和懒汉式的区别

1.饿汉式是空间换时间,懒汉式时间换空间。

2.在多线程访问时,饿汉式不会创建多个对象,懒汉式有可能创建多个对象。

//第三种单例模式
class Singleton {
    private Singleton(){}
    public static final Sigleton s = new Singleton();//被final修饰
}

单例模式的设计场景

1.Runtime

java.lang.Runtime

currentRuntime

饿汉式

public static void main(String[] args) throws IOException {
    Runtime r = Runtime.getRuntime();//获取运行时对象
    //r.exec("shutdown -s -t 300"); 关机
    r.exec("shutdown -a");
}
//在对一个对象进行状态修改的时候

2.Timer 计时器 指定时间执行,定时器

schedul计划

Timertask执行任务

class MyTimerTask extends TimerTask {
    @Override
    public void run() {
        System.out.println("起床背英语单词");
    }
}
public static void main(String [] args) {
    Timer t = new Timer();
    //第一个参数是安排的任务,第二个参数是执行的时间,第三个参数是过多长时间再重复执行。
    t.schedule(new MytimerTask(),new Date(188,6,14,20,30),3000);
    while(true) {
        Thread.sleep(1000);
        System.out.println(new Date());
    }
}

3.两个线程之间通信

  1. 什么时候通信

    • 多个线程并发执行时,在默认情况下CPU是随机切换线程的。
    • 如果我们希望他们有规律的执行,就可以使用通信,例如每个线程执行一次打印
  2. 怎么通信

    • 如果希望线程等待,就调用wait()
    • 如果希望唤醒等待的线程,就调用notify
    • 这两个方法必须在同步代码中执行,并且使用同步锁对象来调用
class Printer {
    private int flag = 1;
    public void print1() {
        synchronized(this) {
            if (flag != 1){
                this.wait();//当前线程等待
            }
            System.out.println("嘿1");
            System.out.println("嘿2");
            System.out.println("嘿3");
            flag = 2;
            this.notify();//随机唤醒单个线程
        }
    }
    public void print2() {
        synchronized(this) {
            if(flag != 2){
                this.wait();
            }
            System.out.println("哈1");
            System.out.println("哈2");
            System.out.println("哈3");
            flag = 1;
            this.notify();
        }
    }
}

public static void main(String[] args) {
    final Printer p = new Printer();
    new Thread() {
        public void run(){
        while(true){
            p.print1();
        }
        }
    }.start();
    
    new Thread() {
        public void run(){
        while(true){
            p.print2();
        }
        }
    }.start();
}

三个或三个线程以上之间的通信

this.notifyAll();

1.5版本之后使用互斥锁

线程间通信的注意事项

  1. 在同步代码块中,用哪个对象锁,就用哪个对象调用wait()方法
  2. 为什么wait方法,和notify方法定义在Object这个类中,因为锁对象可以是任意对象,Object是所有类的基类,所以wait方法和notify方法,需要定义在Object这个类中。
  3. sleep方法和wait()方法的区别:

    • sleep方法必须传入参数,参数就是时间,时间到了自动醒来
    • wait方法可以传入参数也可以不传入参数,传入参数就是在参数的时间结束后等待。不传入参数就是直接等待。
    • sleep方法在同步函数或代码块中,不释放锁,睡着了也抱着锁睡。wait方法在同步函数或者是同步代码块中,释放锁。

JDK1.5新特性 互斥锁

1.同步

线程组概述

  • java中使用ThreadGroup来对线程组进行使用,它可以对一批线程分组管理,
ThreadGroup tg = new ThreadGroup();
Thread t1 = new Thread(tg,mr,"张三");//将线程一放入到组里面

线程的五种状态

新建------start()

就绪------抢到CPU的执行权

运行------sleep()和wait()的方法-------死亡(线程对象变成垃圾)

阻塞-------就绪

线程池的概述和使用

  • 程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中药创建大量生存期很短的线程时,更应该考虑使用线程池。线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在JDK5之前,我们必须手动实现自己的线程池,从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实例
    • 关闭线程池
public static void main (String[] args){
    ExecutorService pool = Executors.newFixedThreadPool(2);
    pool.submit(new MyRunnable());//将线程放进池子里
    pool.submit(new MyRUnnable());
    
    pool.shutdown();//关闭线程池
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        for(int i = 0; i <1000 ; i++) {
            System.out.println(Thread.currentThread().getName()+ "..." + i);
        }
    }
}

多线程的实现方式3

Callable

call()计算结果,如果无法计算结果,抛出异常。

class MyCallable implements Callable<Integer> {
    private int num;
    public MyCallable(int num) {
        this.num = num;
    }
}

@Override
public Integer call()

设计模式 简单工程模式

简单工厂模式概述

  • 又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例。

优点

  • 客户端不需要在负责对象的创建,从而明确了各个类的职责

缺点

  • 这个静态工厂负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护。

案例演示

  • 动物抽象类:public abstract Animal{ public abstraace void eat(); }
  • 具体狗类:public class Dog extends Animal {}
  • 具体猫类:public class Cat extends Animal{}
  • 开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比较麻烦,就需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。
public abstract class Animal {
    public abstract void eat();
}

public class Dog extends Animal {
    @Override
    public void eat() {
        
    }
}
public class Cat extends Animal {
    @Override
    public void eat() {
        
    }
}

public static class AnimalFactory {
    public static Dog createDog() {
        return new Dog();
    }
    public static Cat create() {
        return new Cat();
    }
}

public static void main (String [] args) {
    Dog d = AnimalFactory.createDog();
}

//发现方法会定义很多,复用性太差
//改进一下

public static Animal createAnimal(String name) {
    if("dog".equals(name)){
        retuen new Dog();
    }else if("cat".equals(name)){
        return new Cat();
    }else{
        return null;
    }
}

设计模式(工厂方法模式的概述和使用)

工厂方法模式概述

  • 工厂方法模式中抽象工厂类定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。

优点

  • 客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的代码。后期维护容易。曾倩了系统的扩展性。

缺点

  • 需要额外的编写代码,增加了工作量
public class DogFactory implements Factory {
    @Override
    public Animal createAnimal() {
        return new Dog();
    }
}

GUI(如何创建一个窗口并显示)

面试和开发的时候都不用,这个

适配器设计模式

什么是适配器

  • 在使用监听器的时候,需要定义一个类事件监听接口
  • 通常接口中有多个方法,而程序不一定所有的都用到,但又必须重写,这很繁琐。
  • 适配器简化了这些操作,我们定义监听器时只要继承适配器,然后重写需要的方法即可。

适配器原理

  • 适配器就是一个类,实现了监听器接口,所有抽象方法都重写了,但是方法全是空的。
  • 适配器类需要定义成抽象的,因为创建该类对象,调用空方法是没有意义的。
  • 目的就是为了简化程序员的操作,定义监听器时继承适配器,只重写需要的方法就可以了。
interface 和尚 {
    public void 打坐();
    public void 念经();
    public void 习武();
}

abstract class 天罡星 implements 和尚 {
    @Override
}

class 鲁智深 extends 天罡星 {
    @Override void 习武(){
        //666
    }
}

GUI需要知道的

1.事件处理

  • 事件:用户的一个操作
  • 事件源:被操作的组件
  • 监听器:一个定义类的对象,实现了监听器接口,包含事件处理方法,把监听器添加在事件源上,当事件发生的时候虚拟机就会自动调用监听器中的

本文链接:

https://heyzen.club/index.php/J/273.html
1 + 1 =
快来做第一个评论的人吧~