java基础

java基础-day21-匿名内部类和多线程

2021-06-28  本文已影响0人  触手不可及

匿名内部类和多线程

1. 匿名内部类

1.1 接口你还记得吗???
interface A {
    成员变量 缺省属性 public static final 定义时必须初始化
    成员方法 缺省属性 public abstract 该方法没有方法体
    默认方法 default修饰,当前方法可以拥有方法体 JDK 1.8 新特征
}

一个类遵从接口
class TypeA implements A {
    要求实现接口中所有缺省属性为pubilc abstract成员方法
}

当前类创建对象之后,我们就可以调用当前TypeA类实现接口A 要求完成的方法。
1.2 类的本体
class TypeA implements A {
    @Override
    public void testA() {
        System.out.println("一个类遵从接口A 实现的方法");
    }
}

class TypeB implements A {
    @Override
    public void testA() {
        // TODO Auto-generated method stub
        
    }
}

class Person {
    属性
    方法
    构造方法
}
    这里可以将大括号以内的内容看做是【类的本体】
    TypeA和TypeB这两个类,他们【类的本体】,是因为遵从同一个接口A。这里必须完成对应的方法,该方法就是【类的本体】。而且TypeA和TypeB这两个类最终的目标,就是通过该类对象使用【类本体】中实现的方法。
   开发中我们发现,类的名字貌似太多的约束,并且非常不重要。这里可以采用【匿名内部类方式 Anonymous Inner Type】。
   【最终目的】是为了实现类的本体
package com.qfedu.a_anonymous;

interface SingleDog {
    void test();
}

class SingleDogOne implements SingleDog {
    @Override
    public void test() {
        System.out.println("非诚勿扰,相亲大会,爱情保卫战");
    }
}

public class Demo2 {
    public static void main(String[] args) {
        new SingleDogOne().test();
        
        /*
         * 这里是SingleDog接口的引用数据类型变量,指向一个SingleDog接口对应匿名内部类对象
         * 大括号里面的内容是因为【遵从】接口SingleDog需要完成的方法,也就是【类的本体】。同时
         * 这里隐含一个【遵从关系】。
         * 
         * 当前类的本体没有对应的名字,这就是匿名类!!!
         * 实际上是SingleDog匿名内部类对象赋值给SingleDog接口引用数据类型变量。【多态】
         */
        SingleDog sd = new SingleDog() {
            @Override
            public void test() {
                System.out.println("SingleDog接口匿名内部类对象,赋值给接口引用数据类型变量");
            }
        };
        
        sd.test();
        
        // SingleDog接口匿名内部类的匿名对象,直接调用实现的方法
        new SingleDog() {
            
            @Override
            public void test() {
                System.out.println("SingleDog接口匿名内部类的匿名对象,直接调用实现的方法");
            }
        }.test();
        
        // SingleDog接口匿名内部类的匿名对象 直接作为方法参数
        testAIT(new SingleDog() {
            
            @Override
            public void test() {
                System.out.println("SingleDog接口匿名内部类的匿名对象 直接作为方法参数");
            }
        });
        
        // Lambda表达式!!!
        testAIT(() -> System.out.println("Lambda表达式")); 
    }
    
    public static void testAIT(SingleDog sd) {
        sd.test();
    }
}

2. 多线程

2.1 什么是进程
进程对于计算机而言就是一个独立的程序!!!
例如:
    LOL PUBG WOT CSGO GTA5 QQ 微信

这些程序是向系统申请资源
    CPU 内存 硬盘 网络 GPU
    1. 独立性
    2. 互斥性
    3. 数据独立性
2.2 什么是线程
线程是进程的一部分,通常情况一个进程(程序)都是有多个线程组成的!!!
例如:
    QQ
        私聊 群聊
    LOL 
        游戏 QT 打字
    电脑管家
        电脑体检 垃圾清理 病毒查杀 电脑加速
        
线程使用的是程序内部资源
    每一个线程,都要想程序(进程)申请资源,并且当前很多资源都是【共享资源】
    线程在运行过程中存在很大程度
        【抢占式运行】
    
    目前的操作系统都是"多任务"系统。依赖于在单位时间以内,给不同的程序分出不同的时间片,执行程序,用户的体验就是同时在执行多个程序。
    线程会抢占进程内的时间片.
    
线程存在的特征:
    1. 抢占
    2. 共享资源
    3. 容易导致死锁
2.3 线程和进程的关系
一个进程最少有一个线程!!!
    如果一个进程所有的线程都关闭,那么该进程也会随之关闭!!!

线程是用的是进程中资源。
线程在进程中运行时,是【抢占式】执行!!!

Java中一个Hello World程序,最少有几个线程???
    2 √ 
        1. 主线程
        2. JVM的GC线程 GC垃圾清理!!!
2.4 线程优缺点
优点:
    1. 可以提升用户体验,可以同时执行多个功能
    2. 可以提高资源的利用率
    
缺点:
    1. 线程过多的情况下,会导致计算机卡顿
    2. 占用过多资源
    3. 存在共享资源问题
    4. 极易导致死锁
2.5 Java中创建线程的两种方式【low】
1. 继承Thread类
2. 实现Runnable接口
package com.qfedu.b_thread;

/**
 * 自定义线程类,继承Thread类
 * Thread类是Java中所有线程的基类
 * 
 * @author Anonymous
 *
 */
class MyThread1 extends Thread {
    /*
     * run方法是线程执行方法。
     * 一个线程启动,run方法中的内容就是线程功能代码
     * 
     * What will be run 跑啥
     */ 
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("自定义线程继承Thread类");
        }
        
    }
}

/**
 * 自定义线程类遵从Runnable接口,实现【函数式接口】Runnable接口
 * 唯一方法 run方法
 * @author Anonymous
 *
 */
class MyThread2 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("自定义线程类遵从Runnable接口");
        }
    }
    
}
public class Demo1 {
    public static void main(String[] args) {
        // 继承Thread类自定义线程启动方法
        // 1. 创建自定义线程类对象
        MyThread1 mt1 = new MyThread1();
        
        // 2. 指定start方法,start方法来源于Thread类
        mt1.start();
        
        // 遵从Runnable接口自定义线程启动方法
        // 1. 调用Thread类构造方法 使用Runnable接口的线程类作为构造方法参数
        Thread mt2 = new Thread(new MyThread2());
        
        // 2. 利用Thread类对象启动线程,调用start方法
        mt2.start();
        
        for (int i = 0; i < 100; i++) {
            System.out.println("主线程");
        }
    }
}
以上两种方式,虽然不是最终的线程处理方式,但是我们需要了解一个内容
    1. Java中的继承是单继承还是多继承?
        单继承,Java中的所有类有且只能有一个【直接父类】
    2. Java中一个类遵从接口有限制吗?
        Java中的类可以同时遵从多个接口

如果按照继承Thread类方式来完成自定义线程,那么当前自定义线程类是否还可以继承其他类?
    不能,这里语法存在限制,并且会影响到代码中的逻辑

一个类遵从接口,无非就是增加了一个功能!!!并且不会影响到基本的继承流程!!!

【墙裂推荐】
    自定义线程类遵从Runnable接口实现。

【重点】
调用run方法和start方法有区别吗???
    如果一个线程类对象,调用run方法,那就是一个普通方法。不存在线程运行。
    线程对象有且只有调用start方法启动线程,才算是线程运行!!!
2.6 Thread中常用方法
Constructor
    Thread();
        创建一个线程对象,没有明确的执行目标,并且线程的名字为默认名字
        
    Thread(Runnable target);
        使用Runnable接口的实现类作为当前Thread线程类构造方法参数,Runnable接
        口实现类明确当前线程执行的内容是什么。线程名字为默认名字
        target What will be run? 跑啥
        
    Thread(Runnable target, String name);
        使用Runnable接口的实现类作为当前Thread线程类构造方法参数,Runnable接
        口实现类明确当前线程执行的内容是什么。线程名字为参数指定名字
        target What will be run? 跑啥

Method:
    String getName();
        获取当前线程对象的名字
    void setName(String name);
        设置当前线程对象的名字
    int getPriority()
        获取当前线程对象的优先级,优先级数据范围 【1 ~ 10】 默认为5
        1最低 10最高
    void setPriority(int priority);
        设置当前线程的优先级
        
    static void sleep(int ms);
        在哪一个线程代码中执行,哪一个线程休眠指定的毫秒数
        
    static Thread currentThread();
        在哪一个线程代码中执行,获取当前线程对象
2.7 线程锁操作问题
2.7.1 生活场景分析
电影院
    <<1921>>
    100张票
    美团 猫眼 淘票票

100张票对于三个销售渠道而言,是一个共享资源。并且要求不得重复!!!
2.7.2 代码实现分析
美团,猫眼,淘票票这里可以认为是三个售票线程。

100张票是一个共享资源。而且是三个线程对象共享内容
100张票如何保存,用什么变量保存?
    局部变量
        在方法内定义,从定义位置开始,到当前方法运行结束销毁。不能再次使用。
        局部变量不具有共享数据特征,同时也不具备数据持久化特征
        
        
    成员变量
        成员变量是随着类对象的创建而存在,并且是属于当前类对象的,不同的类对象的
        数据没有任何的共享特征,类对象销毁当前成员变量销毁,所以具有一定的持久
        性。
        
    静态成员变量
        在目前情况下,静态成员变量可以提供给三个线程对象使用,同时也是一个可以满
        足程序从开始到最后退出都可以存在的数据。具有共享特征,同时具有持久化特征
2.7.3 售票抢占问题
image.png
2.7.4 同步代码块
synchronized (锁·对象) {
            
}
    在synchronized 同步代码块以内的内容有且只能允许一个线程存在。一旦有线程进入同步代码块以内,锁对象起作用,不再允许其他线程进入。
    锁对象要求
        1. 被限制的线程使用的锁对象是同一个对象
        2. 锁对象选择不得影响其他功能线程运行。
        3. 锁对象可以采用类锁 SaleTicket.class
        4. 如果在同步代码块内使用sleep方法,会不会开锁???
2.8 守护线程/后台线程
    守护线程/后台线程,大量的充斥在软件中,一般用于在用户不可见情况下偷偷摸摸的做一些事情!!!
    守护线程有一个特征:
        一旦程序中有且只有一个守护线程,当前守护线程会自动销毁。

WeGame  
    LOL大厅等待
    --| 下载更新包 守护线程

守护线程一般用于
    日志记录 数据下载 数据传输 ...
上一篇 下一篇

猜你喜欢

热点阅读