匿名内部类和多线程
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大厅等待
--| 下载更新包 守护线程
守护线程一般用于
日志记录 数据下载 数据传输 ...
网友评论