单例设计模式(重要)

  • 保证类在内存中只有一个对象
  • 饿汉式, 空间换时间, 类创建的时候就创建对象, 线程安全的
  • 懒汉式, 双叫单例加载模式, 使用的时候才创建对象, 存在线程安全问题
  • 区别, 饿汉式空间换时间, 懒汉式时间换空间, 多线程访问时, 饿汉式不会创建多个对象, 懒汉式可能创建多个对象
public class Demo1_Singleton {

    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();

        Singleton s2 = Singleton.getInstance();

        System.out.println(s1);
        System.out.println(s2 == s1);
    }
}

class Singleton{
    // 1. 私有化构造函数, 就不能随意实例类了
    private Singleton (){}

    // 2. 创建实例
    private static Singleton s = new Singleton();



    // 3. 饿汉式
    public static Singleton getInstance() {
        return s;
    }

}

class SingletonLazy{
    private SingletonLazy (){}

    private static SingletonLazy s ;

    public static SingletonLazy getInstance() {
        if(s == null){
            s = new SingletonLazy();
        }
        return s;
    }
}

class SingletonFinal{
    private SingletonFinal(){}
    public static final SingletonFinal s = new SingletonFinal();
}

Runtime 类

  • Process exec(String command) throws IOException 执行命令
import java.io.IOException;

public class Demo2_Runtime {
    public static void main(String[] args) throws IOException {
        Runtime runtime = Runtime.getRuntime();
        runtime.exec("ls");
    }
}

Timer ( 可以被ScheduledExecutorService取代 )

  • 一种工具, 线程用其安排以后在后台线程中执行的任务, 可安排任务执行一次, 或者定期重复执行
private static void demo1() {
    Timer t = new Timer();
//  t.schedule(new MyTimerTask(), new Date(121,8,13,11,8,01);  // 定时 执行
    // 循环执行, 每3秒执行一次
    t.schedule(new MyTimerTask(), new Date(121,8,13,11,8,01),3000);
    while (true){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(new Date());
    }
}

ScheduledExecutorService

  • Time的缺陷, 单线程多个任务排队, 一个任务执行时间长了, 后面任务受影响, 一个任务挂了, 后面的任务无法执行, 强依赖系统时间, 系统时间更改则会更改
  • ScheduledExecutorService 多线程, 则没有上述问题
  • ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) 延时initialDelay, 开始周期delay执行
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Demo3_Timer {
    public static void main(String[] args) throws InterruptedException {
        // 一个任务出现 异常, 不影响其他任务
        ScheduledExecutorService ses = Executors.newScheduledThreadPool(2);
        ses.scheduleAtFixedRate(
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("===" + Thread.currentThread().getName() + "===");
                    }
                }
                , 0, 3, TimeUnit.SECONDS);


        ses.scheduleAtFixedRate(
                new Runnable() {
                    @Override
                    public void run() {
                        int i = 1/0;
                        System.out.println("***" + Thread.currentThread().getName() + "***");
                    }
                }
                , 0, 3, TimeUnit.SECONDS);

    }
    private static void demo2(){
        // 一个任务执行时间长了, 也不会任务其他任务
        ScheduledExecutorService ses = Executors.newScheduledThreadPool(2);
        ses.scheduleAtFixedRate(
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("===" + Thread.currentThread().getName() + "===");
                        try {
                            TimeUnit.SECONDS.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                , 0, 3, TimeUnit.SECONDS);


        ses.scheduleAtFixedRate(
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("***" + Thread.currentThread().getName() + "***");
                    }
                }
                , 0, 3, TimeUnit.SECONDS);
    }

    private static void demo1() {
        Timer t = new Timer();
//        t.schedule(new MyTimerTask(), new Date(121,8,13,11,8,01);  // 定时 执行
        // 循环执行, 每3秒执行一次
        t.schedule(new MyTimerTask(), new Date(121,8,13,11,8,01),3000);
        while (true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(new Date());
        }
    }
}
class MyTimerTask extends TimerTask{
    @Override
    public void run() {
        System.out.println("起来上班");
    }
}

多个线程的通信(重要)

  • this.notify() 随机唤醒单个等待线程
public class Demo1_Notify {
    public static void main(String[] args) {
        Printer p = new Printer();
        new Thread(){
            @Override
            public void run() {
                while (true){
                    try {
                        p.method1();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                while (true){
                    try {
                        p.method2();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}

class Printer{
    private int flag = 1;
    public void method1() throws InterruptedException {
        synchronized (this){
            if(flag != 1){
                this.wait();
            }
            System.out.println("aaaa");
            flag = 2;
            this.notify();
        }
    }
    public void method2() throws InterruptedException {
        synchronized (this){
            if(flag != 2){
                this.wait();
            }
            System.out.println("bbbbbbbb");
            flag = 1;
            this.notify();
        }
    }

}

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

public class Demo2_Notify3 {
    public static void main(String[] args) {
        Printer2 p = new Printer2();
        new Thread(){
            @Override
            public void run() {
                while (true){
                    try {
                        p.method1();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                while (true){
                    try {
                        p.method2();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                while (true){
                    try {
                        p.method3();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}

class Printer2{
    private int flag = 1;
    public void method1() throws InterruptedException {
        synchronized (this){
            while (flag != 1){
                this.wait();
            }
            System.out.println("aaaa");
            flag = 2;
            this.notifyAll();
        }
    }
    public void method2() throws InterruptedException {
        synchronized (this){
            while (flag != 2){
                this.wait();
            }
            System.out.println("bbbbbbbb");
            flag = 3;
            this.notifyAll();
        }
    }
    public void method3() throws InterruptedException {
        synchronized (this){
            while (flag != 3){
                this.wait();
            }
            System.out.println("cccccccccccccc");
            flag = 1;
            this.notifyAll();
        }
    }
}

线程间通信注意的问题

  • 1.在同步代码块中,用哪个对象锁,就用哪个对象调用wait方法
  • 2.为什么wait方法和notify方法定义在Object这类中?
    • 因为锁对象可以是任意对象,Object是所有的类的基类,所以wait方法和notify方法需要定义在Object这个类中
  • 3.sleep方法和wait方法的区别?
    • a,sleep方法必须传入参数,参数就是时间,时间到了自动醒来
    • wait方法可以传入参数也可以不传入参数,传入参数就是在参数的时间结束后等待,不传入参数就是直接等待
    • b,sleep方法在同步函数或同步代码块中,不释放锁,睡着了也抱着锁睡
    • wait方法在同步函数或者同步代码块中,释放锁

互斥锁(重要) ReentrantLock Condition

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Demo3_ReentrantLock {
    public static void main(String[] args) {
        Printer3  p = new Printer3();
        new Thread(){
            @Override
            public void run() {
                while (true) {
                    try {
                        p.method1();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                while (true) {
                    try {
                        p.method2();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                while (true) {
                    try {
                        p.method3();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

    }
}
class Printer3{
    private int flag = 1;
    private ReentrantLock r = new ReentrantLock();
    Condition c1 = r.newCondition();
    Condition c2 = r.newCondition();
    Condition c3 = r.newCondition();
    public void method1() throws InterruptedException {
        r.lock();
            if (flag != 1){
                c1.await();
            }
            System.out.println("aaaa");
            flag = 2;
            c2.signal();
        r.unlock();
    }
    public void method2() throws InterruptedException {
        r.lock();
        if (flag != 2){
                c2.await();
            }
            System.out.println("bbbbbbbb");
            flag = 3;
            c3.signal();
        r.unlock();
    }
    public void method3() throws InterruptedException {
        r.lock();
            if(flag != 3){
                c3.await();
            }
            System.out.println("cccccccccccccc");
            flag = 1;
            c1.signal();
        r.unlock();
    }
}

线程组

public class Demo4_ThreadGroup {
    public static void main(String[] args) {
//        demo1();
        ThreadGroup threadGroup = new ThreadGroup("自造线程组");
        Mythread mythread = new Mythread();
        Runnable target;
        Thread t1 = new Thread(threadGroup, mythread);
        Thread t2 = new Thread(threadGroup,mythread,"线程1");
        Thread t3 = new Thread(threadGroup,mythread,"线程2");

        System.out.println(t1.getName());
        System.out.println(t2.getName());
        System.out.println(t3.getName());

        System.out.println(t1.getThreadGroup().getName());
        System.out.println(t2.getThreadGroup().getName());
        System.out.println(t3.getThreadGroup().getName());

        System.out.println(t1.getThreadGroup().getParent().getName());
    }

    private static void demo1() {
        Mythread mythread = new Mythread();
        Thread t1 = new Thread(mythread);
        Thread t2 = new Thread(mythread);

        ThreadGroup tg1 = t1.getThreadGroup();
        ThreadGroup tg2 = t2.getThreadGroup();
        System.out.println(tg1.getName());
        System.out.println(tg2.getName());
    }
}

class Mythread implements Runnable{
    @Override
    public void run() {

    }
}

线程的5种状态

  • 新建线程.start() -> 线程就绪状态, 有执行权->抢到CPU执行权限执行->死亡状态, run执行完了
  • 抢到CPU执行权限执行->wait或sleep线程阻塞->叫醒线,程线程就绪状态, 有执行权

线程池

  • 程序创建一个线程成本比较高, 为了方便使用线程池, 使用后再返给JVM
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo5_Executors {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(2);
        pool.submit(new Mythread());
        pool.submit(new Mythread());

        pool.shutdown();
    }
}

实现Callable的线程

import java.util.concurrent.*;

public class Demo6_Callable {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(2);
        Future<Integer> f1 =  pool.submit(new MyCallable(10));
        Future<Integer> f2 =  pool.submit(new MyCallable(20));
        System.out.println(f1.get());
        System.out.println(f2.get());

        pool.shutdown();
    }

}
class MyCallable implements Callable<Integer>{
    private int num;
    public MyCallable(int num){
        this.num = num;
    }
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for(int i=1;i<num;i++){
            sum = sum + i;
        }
        return sum;
    }
}

简单工厂模式

  • 概述 静态工厂方法模式, 它定义一个具体的工厂类负责创建一些类的实例
  • 优点 客户端不负责对象的创建, 从而明确各类的职责
  • 缺点 静态工厂负责所有类的创建, 如果有新的对象或者新对象创建方式不同, 就需要不断修改工厂类, 不利于后期维护.
public abstract class Animal {
    public void eat(){};
}
public class AnimalFactory {
    public static Dog createDog(){
        return new Dog();
    }
    public static Cat createCat(){
        return new Cat();
    }
    public static Animal createAnimal(String animal){
        if( "dog".equals(animal)){
            return new Dog();
        } else if( "cat".equals(animal)){
            return new Cat();
        }
        return null;
    }
}
public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("单身狗儿吃狗粮");
    }
}

``

public class Test {
    public static void main(String[] args) {
        Dog dog = AnimalFactory.createDog();
        System.out.println(dog);

        Dog d = (Dog) AnimalFactory.createAnimal("dog");
        d.eat();

        Cat c = (Cat) AnimalFactory.createAnimal("cat");
        c.eat();
    }
}

工厂方法模式

  • 工厂方法模式中看网易工厂类负责定义创建对象的接口, 具体对象的创建工作由继承工厂的具体类实现
  • 做点
    • 客户端不需要在负责对象的创建, 从而明确了各个类的职责, 如果有新的对象增加, 只需要增加一个具体的类和
    • 俱体的工厂类即可, 不影响已有的代码, 后期维护容易, 增强了系统扩展性
  • 缺点 需要额外编写代码, 增加工作量
public abstract class Animal {
    public void eat(){};
}
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("单身狗儿吃狗粮");
    }
}
public interface Factory {
    public Animal createAnimal();
}
public class CatFactory implements Factory{
    @Override
    public Animal createAnimal() {
        return new Cat();
    }
}
public class DogFactory implements Factory{
    @Override
    public Animal createAnimal() {
        return new Dog();
    }
}
public class Test {
    public static void main(String[] args) {
        DogFactory dogFactory = new DogFactory();
        Dog d = (Dog) dogFactory.createAnimal();
        d.eat();

        CatFactory catFactory = new CatFactory();
        Cat c = (Cat) catFactory.createAnimal();
        c.eat();
    }
}

Gui 了解, 暂用不到

import java.awt.*;

public class Demo1_Frame {
    public static void main(String[] args) {
        Frame f = new Frame();

        f.setTitle("我的窗口");
        f.setLocation(500,400);
        f.setSize(400,300);
        f.setIconImage(Toolkit.getDefaultToolkit().createImage("favicon.png"));
        f.setVisible(true);
    }
}

布局和按钮

import java.awt.*;

public class Demo1_Frame {
    public static void main(String[] args) {
        Frame f = new Frame();

        f.setTitle("我的窗口");
        f.setLocation(500,400);
        f.setSize(400,300);
        f.setIconImage(Toolkit.getDefaultToolkit().createImage("favicon.png"));
        f.setLayout(new FlowLayout());
        Button button = new Button("按钮");
        Button button2 = new Button("按钮");
        f.add(button);
        f.add(button2);

        f.setVisible(true);
    }
}

监听的3种方式

  • 类实现WindowListener接口
  • 类继承WindowAdapter
  • 匿名内部类 new WindowAdapter()
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

public class Demo1_Frame {
    public static void main(String[] args) {
        Frame f = new Frame();

        f.setTitle("我的窗口");
        f.setLocation(500,400);
        f.setSize(400,300);
        f.setLayout(new FlowLayout());
        Button button = new Button("按钮");
//        MyWindow myWindow = new MyWindow();
//        f.addWindowListener(myWindow);
//        MyAdapter myAdapter = new MyAdapter();
//        f.addWindowListener(myAdapter);
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        f.add(button);

        f.setVisible(true);
    }
}

class MyAdapter extends WindowAdapter{
    @Override
    public void windowClosing(WindowEvent e) {
        System.exit(0);
    }
}

class MyWindow implements WindowListener{
    @Override
    public void windowOpened(WindowEvent e) {
    }

    @Override
    public void windowClosing(WindowEvent e) {
        System.exit(0);
    }

    @Override
    public void windowClosed(WindowEvent e) {
        System.out.println("Colosed");
    }

    @Override
    public void windowIconified(WindowEvent e) {
    }

    @Override
    public void windowDeiconified(WindowEvent e) {
    }
    @Override
    public void windowActivated(WindowEvent e) {

    }
    @Override
    public void windowDeactivated(WindowEvent e) {
    }
}

鼠标监听

  • 同样有3种方式
  • 实现MouseListener 接口
  • 继承MouseAdapter抽象类
  • 匿名内部类new MouseAdapter
import java.awt.*;
import java.awt.event.*;

public class Demo1_Frame {
    public static void main(String[] args) {
        Frame f = new Frame();

        f.setTitle("我的窗口");
        f.setLocation(500,400);
        f.setSize(400,300);
        f.setLayout(new FlowLayout());
        Button button = new Button("按钮");
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        f.add(button);
        button.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                System.exit(0);
            }
        });

        f.setVisible(true);
    }
}

键盘监听和键盘事件

  • 实现KeyListener 接口
  • 继承 KeyAdapter 抽象类
  • 匿名内部类new KeyAdapter()
import java.awt.*;
import java.awt.event.*;

public class Demo1_Frame {
    public static void main(String[] args) {
        Frame f = new Frame();

        f.setTitle("我的窗口");
        f.setLocation(500,400);
        f.setSize(400,300);
        f.setLayout(new FlowLayout());
        Button button = new Button("按钮");
//        MyWindow myWindow = new MyWindow();
//        f.addWindowListener(myWindow);
//        MyAdapter myAdapter = new MyAdapter();
//        f.addWindowListener(myAdapter);
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        f.add(button);
        button.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                System.exit(0);
            }
        });
        button.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                if(e.getKeyCode() == KeyEvent.VK_SPACE){
                    System.exit(0);
                }
            }
        });

        f.setVisible(true);
    }
}

动作监听

  • 实现ActionListener 接口
  • 匿名内部类 new ActionListener()类
import java.awt.*;
import java.awt.event.*;

public class Demo1_Frame {
    public static void main(String[] args) {
        Frame f = new Frame();

        f.setTitle("我的窗口");
        f.setLocation(500,400);
        f.setSize(400,300);
        f.setLayout(new FlowLayout());
        Button button = new Button("按钮");
        Button button2 = new Button("按钮二");
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        f.add(button);
        f.add(button2);
        button.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                System.exit(0);
            }
        });
        button.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                if(e.getKeyCode() == KeyEvent.VK_SPACE){
                    System.exit(0);
                }
            }
        });
        button2.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        f.setVisible(true);
    }
}

设计模式-适配器模式

  • 什么是适配器
    • 在使用监听器的时候, 需要定义一个事件监听器的接口
    • 通常接口中有多个方法, 而程序中不一定所有的都用到, 但又必须重写, 这很繁琐
    • 我在楼下器简化了这些操作, 我们定义监听器时只要继承我在楼下器, 然后重写需要的方法即可
  • 适配器原理
    • 适配器就是一个类, 实现了监听器接口, 所有抽象方法都重写了, 但是方法全是空的
    • 我在楼下器类需要定义成抽象的, 因为创建类对象, 调用空方法是没有意义的
    • 目的就是为了简化程序员的操作, 定义监听时继承适配器, 中重写需要的方法就可以了

GUI(需要知道的)

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