文章目录
一、尚硅谷模块
1.1、第一季大佬总结
1.1.2、我的一些补充
1.1.2.1、 单例设计模式
饿汉式
/**
* @Author ljm
* @Date 2021/10/19 21:43
* @Version 1.0
* 饿汉式:
* 直接创建实例对象,不管你是否需要这个对象都会创建
*
* (1)构造器私有化
* (2)自行创建,并用静态变量保存
* (3)向外提供这个实例
* (4)强调这是一个单例,我们可以用final修改
*/
public class Singleton1 {
// final 一旦赋值这个变量就不能再修改
//static 用法 https://blog.csdn.net/LIAO_7053/article/details/81408139?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link
//static final全局常量
public static final Singleton1 INSTANCE = new Singleton1();
public Singleton1() {
}
}
测试
import com.atguigu.single.Singleton1;
/**
* @Author ljm
* @Date 2021/10/19 22:09
* @Version 1.0
*/
public class TestSingleton1 {
public static void main(String[] args) {
Singleton1 s = Singleton1.INSTANCE;
}
}
枚举类型
/**
* @Author ljm
* @Date 2021/10/19 22:04
* @Version 1.0
* 枚举类型:表示该类型的对象是有限的几个
* 我们可以限定为一个,就成了单例
*/
/**
* Java 枚举(enum)
* Java 枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一个年的 12 个月份,一个星期的 7 天,方向有东南西北等。
*
* Java 枚举类使用 enum 关键字来定义,各个常量使用逗号 , 来分割。
*/
public enum Singleton2 {
INSTANCE;
}
测试
import com.atguigu.single.Singleton2;
/**
* @Author ljm
* @Date 2021/10/19 22:09
* @Version 1.0
*/
public class TestSingleton2 {
public static void main(String[] args) {
Singleton2 s = Singleton2.INSTANCE;
System.out.println(s);
}
}
静态代码块饿汉式(适合复杂实例化)
package com.atguigu.single;
import java.io.IOException;
import java.util.Properties;
/**
* @Author ljm
* @Date 2021/10/19 21:43
* @Version 1.0
*
*/
public class Singleton3 {
//第一种方法在这个地方直接new
// public static final Singleton3 INSTANCE = new Singleton3();
//第二种方法
//static 用法 https://blog.csdn.net/LIAO_7053/article/details/81408139?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link
public static final Singleton3 INSTANCE;
private String info;
static {
Properties pro = new Properties();
try {
pro.load(Singleton3.class.getClassLoader().getResourceAsStream("single.properties"));
INSTANCE = new Singleton3(pro.getProperty("info"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public Singleton3(String info) {
this.info = info;
}
public static Singleton3 getINSTANCE() {
return INSTANCE;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "Singleton3{" +
"info='" + info + '\'' +
'}';
}
}
测试
import com.atguigu.single.Singleton3;
/**
* @Author ljm
* @Date 2021/10/19 22:09
* @Version 1.0
*/
public class TestSingleton3 {
public static void main(String[] args) {
Singleton3 s = Singleton3.INSTANCE;
System.out.println(s);
}
}
src/main/resources/single.properties
info=atguigu
懒汉式:延迟创建对象
线程不安全(适用于单线程)
package com.atguigu.single;
/**
* @Author ljm
* @Date 2021/10/19 22:04
* @Version 1.0
* 懒汉式:
* 延迟创建这个实例对象
* (1)构造器私有化
* (2)用一个静态变量保存这个唯一的实例
* (3)要提供一个静态方法来获取这个实例对象
*/
public class Singleton4 {
private static Singleton4 instance;
private Singleton4() {
}
public static Singleton4 getInstance() {
if (instance == null) {
// try {
// Thread.sleep(200);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
instance = new Singleton4();
}
return instance;
}
}
测试
修改懒汉式代码
package com.atguigu.single;
/**
* @Author ljm
* @Date 2021/10/19 22:04
* @Version 1.0
* 懒汉式:
* 延迟创建这个实例对象
* (1)构造器私有化
* (2)用一个静态变量保存这个唯一的实例
* (3)要提供一个静态方法来获取这个实例对象
*/
public class Singleton4 {
private static Singleton4 instance;
private Singleton4() {
}
public static Singleton4 getInstance() {
if (instance == null) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton4();
}
return instance;
}
}
import com.atguigu.single.Singleton4;
import java.util.concurrent.*;
/**
* @Author ljm
* @Date 2021/10/20 9:26
* @Version 1.0
*/
public class TestSingleton4 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// Singleton4 s1 = Singleton4.getInstance();
// Singleton4 s12 = Singleton4.getInstance();
// System.out.println(s1 == s12);
// System.out.println(s1);
// System.out.println(s12);
//Callable用法
//https://ghsau.blog.csdn.net/article/details/7451464?spm=1001.2101.3001.6650.13&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-13.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-13.no_search_link
// call 方法可以有返回值,run方法没有
Callable<Singleton4> c = new Callable<Singleton4>() {
public Singleton4 call() throws Exception {
return Singleton4.getInstance();
}
};
//创建两个线程的线程池
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<Singleton4> f1 = executor.submit(c);
Future<Singleton4> f2 = executor.submit(c);
Singleton4 s1 = f1.get();
Singleton4 s2 = f2.get();
//是有概率问题的一会true一会false
System.out.println(s1 == s2);
System.out.println(s1);
System.out.println(s2);
executor.shutdown();
}
}
不同线程遇到延迟会产生阻塞,这样会从造成一会true一会false的情况,不同线程遇到休眠会产生阻塞,可能会出现线程由于时间不同造成创建两个不同对象的情况。
线程安全适用于多线程
package com.atguigu.single;
/**
* @Author ljm
* @Date 2021/10/19 22:04
* @Version 1.0
* 懒汉式:
* 延迟创建这个实例对象
* (1)构造器私有化
* (2)用一个静态变量保存这个唯一的实例
* (3)要提供一个静态方法来获取这个实例对象
*/
public class Singleton5 {
private static Singleton5 instance;
private Singleton5() {
}
public static Singleton5 getInstance() {
//https://blog.csdn.net/luoweifu/article/details/46613015 synchronized用法
//安全问题已经解决但是我需要解决效率问题加个null判断
if(instance == null) {
synchronized(Singleton5.class){
if (instance == null) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton5();
}
}
}
return instance;
}
}
测试
import com.atguigu.single.Singleton4;
import com.atguigu.single.Singleton5;
import java.util.concurrent.*;
/**
* @Author ljm
* @Date 2021/10/20 9:26
* @Version 1.0
*/
public class TestSingleton5 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// Singleton4 s1 = Singleton4.getInstance();
// Singleton4 s12 = Singleton4.getInstance();
// System.out.println(s1 == s12);
// System.out.println(s1);
// System.out.println(s12);
//Callable用法
//https://ghsau.blog.csdn.net/article/details/7451464?spm=1001.2101.3001.6650.13&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-13.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-13.no_search_link
// call 方法可以有返回值,run方法没有
Callable<Singleton5> c = new Callable<Singleton5>() {
public Singleton5 call() throws Exception {
return Singleton5.getInstance();
}
};
//创建两个线程的线程池
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<Singleton5> f1 = executor.submit(c);
Future<Singleton5> f2 = executor.submit(c);
Singleton5 s1 = f1.get();
Singleton5 s2 = f2.get();
//是有概率问题的一会true一会false
System.out.println(s1 == s2);
System.out.println(s1);
System.out.println(s2);
executor.shutdown();
}
}
无论如何修改延迟时间我们发现都是true
静态内部类形式(适用于多线程)
package com.atguigu.single;
/**
* @Author ljm
* @Date 2021/10/20 10:10
* @Version 1.0
* 在内部类被加载和初始化时,才创建INSTANCE
* 静态类不会随着外部类的加载和初始化而初始化,它是要单独加载和初始化的
* 因为在内部类加载和初始化时创建的因此是线程安全的
*/
public class Singleton6 {
private Singleton6(){
}
private static class Inner{
private static final Singleton6 INSTANCE = new Singleton6();
}
public static Singleton6 getInstance() {
return Inner.INSTANCE;
}
}
1.1.1.2、基本数据类型和引用类型
对应尚硅谷第一季的4、方法参数传递机制章节
Java基本类型共有八种,基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double。数值类型又可以分为整数类型byte、short、int、long和浮点数类型float、double。
引用类型包括三种:
类 Class
接口 Interface
数组 Array
方法的参数传递机制
1、形参是基本数据类型
传递数据值
2、实参是引用数据类型
传递地址值
特殊的类型:String、包装类等对象的不可变性
1.2.3、 5、递归与迭代
首先看一道编程题如下:
有 n 步台阶,一次只能上 1 步或者 2 步,共有多少种走法?
1、递归fen
分析如图,当n等于1或者2时,走法就等于n,从第三层台阶开始,每一层台阶为前两层台阶走法之和。
2、迭代
用 one、two 这两个变量来存储 n 的最后走一步和最后走两步,从第三层开始走,用 sum 来保存前两次的走法的次数,sum = two + one; 然后 two 移到 one,one 移到 sum 循环迭代。
代码如下:
/**
* 编程题:有 n 步台阶,一次只能上 1 步或者 2 步,共有多少种走法
*/
public class Code_05_StepProblem {
@Test
public void test() {
// 时间复杂度 ...
// long start = System.currentTimeMillis();
// System.out.println(recursion(40)); // 165580141
// long end = System.currentTimeMillis(); // 537
// System.out.println(end - start);
// 时间复杂度 O(n)
long start = System.currentTimeMillis();
System.out.println(iteration(40)); // 165580141
long end = System.currentTimeMillis(); // 0
System.out.println(end - start);
}
// 递归实现
public int recursion(int n) {
if(n < 1) {
return 0;
}
if(n == 1 || n == 2) {
return n;
}
return recursion(n - 2) + recursion( n - 1);
}
// 迭代实现
public int iteration(int n) {
if(n < 1) {
return 0;
}
if(n == 1 || n == 2) {
return n;
}
int two = 1; // 一层台阶,有 1 走法, n 的前两层台阶的走法
int one = 2; // 二层台阶,有 2 走法, n 的前一层台阶的走法
int sum = 0; // 记录一共有多少中走法
for(int i = 3; i <= n; i++) {
sum = two + one;
two = one;
one = sum;
}
return sum;
}
}
总结:
1)方法调用自身称为递归,利用变量的原值推出新值称为迭代。
2)递归
优点:大问题转为小问题,可以减少代码量,同时代码精简,可读性好;
缺点:递归调用浪费了空间,而且递归太深容易造成堆栈的溢出。
3)迭代
优点:代码运行效率好,因为时间复杂度为0(n),而且没有额外空间的开销;
1.2.4、Spring Bean 的作用域之间有什么区别?
默认情况下,Spring只为每个在I0C容器里声明的bean创建唯一一个实例,整个IOC容器范围内都能共享该实例:所有后续的getBean()调用和bean引用都将返回这个唯一的bean实例。该作用域被称为singleton,它是所有bean的默认作用域。
在Spring的配置文件中,给bean加上scope属性来指定bean的作用域如下:
singleton:唯一 bean 实例,Spring 中的 bean 默认都是单例的。
prototype:每次请求调用getBean()都会创建一个新的 bean 实例。
request: 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前WebApplicationContext内有效。
session:每一次 HTTP 请求都会产生一个新的 bean,不同的HTTP session 使用不用的bean,该 bean 仅在当前WebApplicationContext内有效。
global-session:全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码(例如:HTML)片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。
1.2.5、mysql主键外键
第二季
2.1、大佬总结
2.2、我的一些补充
并发:多个线程非同时但一块执行;并行:多个线程同时一块执行;
StackoverFlowError
堆栈溢出,我们有最简单的一个递归调用,就会造成堆栈溢出,也就是深度的方法调用
栈一般是512K,不断的深度调用,直到栈被撑破
OutOfMemoryError java heap space
创建了很多对象,导致堆空间不够存储
OOM之Metaspace
永久代(Java8后被原空向Metaspace取代了)存放了以下信息:
虚拟机加载的类信息
常量池
静态变量
即时编译后的代码
注意:这里的常量池是指的运行时常量池,并非string table(字符串常量池)
这里有点问题,字符串常量池和静态变量在1.7及其之后就放入了堆中,参考宋红康老师的
STW
停顿时间