接口
含义
是一种特殊的抽象类,是一种约束、规范。
特殊性
- 第一没有具体(普通)方法,但是1.8之后可以有默认实现方法
- 抽象方法默认会添加public abstract 修饰符(要么写对,要么不写)
- 字段会默认添加public static final 修饰符(要么写对,要么不写)
- 接口是可以继承多个接口的
- 接口中的内部类的修饰符 public static(要么写对,要么不写)
- 接口有构造器吗?TODO
案例
自行设计
内部类
含义
类里面的类
分类
- 方法内部类
- 成员内部类
- static修饰内部类
- 非static修饰的内部类
案例
自行设计
包装数据类型
含义
8大基本数据类型都有对应的引用数据类型。
-
byte Byte
-
int Integer
-
short Short
-
long Long
-
char Character
-
float Float
-
double Double
-
boolean Boolean
为什么使用包装数据类型
-
基本数据类型和包装数据类型的默认值不一样
-
包装数据类型提供了很多API
常用API(Integer为例)
- parseInt
- valueOf
- intValue
- compare
- 等等
装箱
含义
基本数据变成包装数据类型
种类
- 自动装箱(经过发现在编译的时候调用了手动装箱的方法)
- 手动装箱
案例
自行编写
拆箱
含义
包装数据类型变成基本数据
种类
- 自动拆箱(经过发现在编译的时候调用了手动拆箱的方法)
- 手动拆箱
案例
自行编写
享元设计模式
含义
共享缓存设计默认
使用场景
有一些对象要经常使用的时候,我们可以提前将这些对象创建好并放入缓存中,下次使用直接从缓存获取.
包装数据类型中大量使用,建议自行查看
异常
含义
也称为异常事件,在软件运行时,很多情况都会导致异常事件的发生。比如:文件不存在、网络断开、访问的数据库打不开、类找不到、0/0、空指针
异常处理机制
当一个方法在运行时发生异常事件时候,该方法会创建一个异常对象,必将该对象抛给运行时系统(即:抛出遗产),该异常对象包含了异常的所有信息,包括异常类型、调用过程、第几行代码等。
异常处理种类
- 捕获
- 抛出异常
异常体系
TODO
自定义异常
TODO
线程
常见概念
-
串行
多个事件依次执行
-
并行
同一时刻多个事件同时进行
-
并发
一段时间内多个事件的发生。
进程
正在运行的程序,进程有自己独立的内存空间。
至少有一个线程
线程
含义
执行的索引 TODO
执行过程
从宏观角度上理解线程是并行运行的,但是从微观角度上是交替执行的(并发),当系统只有一个CPU时,会以某种顺序执行多个线程这就是线程调度。
创建方式
- 继承Thread
- 实现Runnable接口
方式一
public class ThreadFirstDemo {
//串行:多个事件依次执行
//并行:同一时刻多个事件一起发生
//并发:一段时间内多个事件的发生
//进程
//含义:
//正在运行的程序
//有独立的内存空间,至少有个一个线程
//线程
//含义:执行的索引(分支)
//创建方式
//extends Thread
//implements Runnabel
public static void main(String[] args) {
//main 主线程
//Thread.currentThread() 获取当前线程
//Thread.currentThread().getName() 获取当前线程的名字
System.out.println("开始");
//创建一个线程
Thread buyThread = new BuyThread();
//启动 调用start方法
buyThread.start();
int i=10;
while(i>0){
System.out.println("main 结束"+i);
i--;
}
//思考
//哪个线程先执行完??
}
}
class BuyThread extends Thread{
//重写run方法,run就是当前线程的任务
@Override
public void run() {
int i=10;
while(i>0){
System.out.println("购买了第"+i+"次");
i--;
}
}
}
方式二
public class ThreadSecondDemo {
public static void main(String[] args) {
//创建线程
Runnable runnable = new BuyTicketThread();
//第一个线程
Thread one = new Thread(runnable,"小红");
//第二个线程
Thread two = new Thread(runnable,"小亮");
//启动线程 start
one.start();
two.start();
}
}
class BuyTicketThread implements Runnable{
int count = 40;
@Override
public void run() {
//线程的任务
while(count > 0){
//Thread.currentThread().getName() 获取当前线程名
System.out.println(Thread.currentThread().getName()+"购买的门票编号是"+count);
count--;
}
}
}
区别
- 继承方式不能在继承其他类,实现方式还可以继承其他类
- 继承方式资源不共享,实现方式资源共享
- 实现方式
多线程安全
含义
多个线程修改同一份资源,造成数据混乱。
处理方式
- 同步机制
- 同步方法
- 不同代码块
- 可重入锁
案例
public class SafeTest {
public static void main(String[] args) {
Runnable runnable = new BuyTicketThread();
//第一个线程
Thread one = new Thread(runnable,"小红");
//第二个线程
Thread two = new Thread(runnable,"小亮");
//启动线程 start
one.start();
two.start();
}
}
class BuyTicketThread implements Runnable{
int count = 40;
//可重入锁
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
System.out.println("来抢票。。。");
lock.lock();
try {
while(count > 0){
System.out.println(Thread.currentThread().getName()+"购买的门票编号是"+count);
count--;
}
} finally {
lock.unlock();
}
}
//同步代码块
/*
@Override
public void run() {
System.out.println("来抢票。。。");
//监视对象
//如果该方法不是静态的,一般写this
//如果该方法是静态的,一般写类名.class //字节码对象
synchronized(this){
while(count > 0){
System.out.println(Thread.currentThread().getName()+"购买的门票编号是"+count);
count--;
//休眠且释放锁,当时间到达的时候会继续执行
try {
wait(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
*/
//同步方法
//如果方法是非static,此时监视对象就是this
//如果方法是static,此时监视对象就是类名.class
/*
@Override
public synchronized void run() {
System.out.println("来抢票。。。");
while(count > 0){
//Thread.currentThread().getName() 获取当前线程名
System.out.println(Thread.currentThread().getName()+"购买的门票编号是"+count);
count--;
if(count%4==0){
try {
//Thread.sleep(100); //不会释放锁
wait(100); //等待,会释放锁的 //小亮
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
*/
}
单例设计模式
懒汉式
第一次使用的时候才会去创建对应的对象。
案例
public class LazySingle {
public static void main(String[] args) {
ATM atm1 = ATM.getInstance();
ATM atm2 = ATM.getInstance();
System.out.println(atm1==atm2);
}
}
class ATM{
private static ATM atm;
private ATM(){
}
public static final ATM getInstance(){
if(atm==null){
synchronized(ATM.class){
if(atm==null){
atm = new ATM();
}
}
}
return atm;
}
private void saveMeney(){
System.out.println("存钱");
}
}
Object常用方法
- hasCode
- toString
- equals
- getClass
- finalize
- wait(long time) //等待且释放锁,时间到了之后会继续执行
- wait() //无限等待且释放锁,唤醒之后会继续执行
- notify() //唤醒其中一个等待的线程
- notifyAll() //唤醒所有等待的线程
线程常用方法
- Thread.getCuurentThread();
- Thread.sleep //等待,不会释放锁
- getName
- setName
- getId
- setPriority
- getPriority
- join
生产者消费者
public class Factory {
private String name;
//代表有没有
private boolean isEmpty = true;
//synchronized 监视对象this
/**
* 生产
* @param name
*/
public synchronized void push(String name){
while(!isEmpty){ //produce
//...不空,等待直到被消费
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name;
System.out.println("生产了="+name);
isEmpty = false;
notifyAll();
}
/**
* 消费
*/
public synchronized void pop(){
while(isEmpty){
//不能消费,需要等待
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//代表 可以消费
System.out.println("消费了="+name);
isEmpty = true;
notifyAll();
}
}
public class Producer extends Thread{
private Factory factory;
public Producer(Factory factory){
this.factory = factory;
}
@Override
public void run() {
int i = 10;
while(i>0){
factory.push(i%2==0?"西瓜":"哈密瓜");
i--;
}
}
}
public class Comsumer extends Thread{
private Factory factory;
public Comsumer(Factory factory){
this.factory = factory;
}
@Override
public void run() {
int i = 10;
while(i>0){
factory.pop();
i--;
}
}
}
public class Test {
public static void main(String[] args) {
Factory factory = new Factory();
Producer produce = new Producer(factory);
Comsumer comsume = new Comsumer(factory);
produce.start();
comsume.start();
}
}
线程控制
TODO
线程生命周期
定时器
使用Timer的schedule,schedule有3个参数:
schedule(TimerTask task, long delay, long period)第一个为定时任务,
根据业务需要重写TimerTask的run方法即可;
第二个为延时启动,单位毫秒;
第三个位多久运行一次,单位毫秒;
new Timer().schedule(new TimerTask() {
@Override
public void run() {
try {
//do Something
} catch (Exception e) {
e.printStackTrace();
}
}
},0,5L * 60 * 1000);
作业
-
自行学习java定时器
-
自行编写生产者消费者案例
-
自行编写2个线程抢票,且机会平局
-
自行总结线程生命周期
-
如下程序是否合理
int a = 10; //假设该变量从控制台输入 int b = 20; if(a-b>0){ System.out.println("a大"); }
-
自行分析如下程序
Integer a = 10; Integer b = 10; syso(a==b); //结果是什么?为什么? a = 200; b =200; syso(a==b); //结果是什么?为什么? a = new Integer(1); b = new Integer(1); syso(a==b); //结果是什么?为什么?
-
自行编写一个User的享元设计模式。
要求:
当创建zs,ls,zl,ww 这些常用名称的User对象的时候从缓存中获取并返回
当创建其他名称的User对象的时候直接new对象并返回