Day 15
一、设计模式
软件设计模式(Software Design Pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性。
即:前辈们对代码的总结(代码实现的套路)
单例模式
单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。例如,Windows 中只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容的不一致等错误。
在计算机系统中,还有 Windows 的回收站、操作系统中的文件系统、多线程中的线程池、显卡的驱动程序对象、打印机的后台处理服务、应用程序的日志对象、数据库的连接池、网站的计数器、Web 应用的配置对象、应用程序中的对话框、系统中的缓存等常常被设计成单例。
单例模式有 3 个特点:
- 单例类只有一个实例对象;
- 该单例对象必须由单例类自行创建;
- 单例类对外提供一个访问该单例的全局访问点;
-
单例模式: 保证一个只能存在一个实例
-
懒汉式 : 实例等到调用方法时候创建(调用的时候,最后一刻) ---线程不安全,效率较高
-
饿汉式: 类第一次加载之后就会创建实例 ---线程安全,效率较低
-
静态的内容(静态变量,静态块),在类第一次加载之后就会初始化
-
实现方式:
-
1.构造器私有化(外部才不能通过new随便创建对象,对象只能我[类的内部]来创建,给你)
-
2.私有的,静态的,该类的引用(存储创建了的对象)
-
3.对外提供一个公共的静态的访问方式(方法)
1.饿汉式
class Single{
//2.私有的静态的Single类型的引用
private static Single single = new Single(); //静态变量会在类第一次加载后初始化,就会创建实例
//1.私有的构造器
private Single() {
// TODO Auto-generated constructor stub
}
//3.公共方法 返回一个当前类型的对象
public static Single newInstance() {
return single;
}
}
2.懒汉式
class SingleTon{
//2私有的静态的该类的引用
private static SingleTon singleTon;
//1.私有的构造器
private SingleTon(){}
//3.公共的静态的访问方式,返回该类实例
public static SingleTon newInstance() {
//创建对象
//第一次调用方法时候才创建对象,第二次开始就不创建,因为已经有了,直接返回
if(singleTon == null) {
singleTon = new SingleTon();
}
return singleTon;
}
二、多线程 Thread
1.定义
多任务同时执行,多条路径可以同时执行,如果没有多任务,就不需要开启多线程
多线程,说白了就是多条执行路径,原来是一条路径,就主路径(main),现在是多 条路径。
2.进程和线程之间的区别
-
进程:资源分配的最小单位 (程序) 一个进程包含1~n个线程 ,每一个进程都有自己的代码和运行空间, 进程之间切换开销大
-
线程:cpu调度的最小单位(程序中真实运行的) ,一系列线程共享当前进行的资源 线程之间切换开销小 ,每个线程都有自己的运行栈和程序计数器
-
并行和串行
-
并行: 真的同时执行
-
串行: 快速切换
-
多线程(机制)和并发(事件触发情况) --->了解
3.优缺点
-
多线程的优点: 资源利用率更好,效率更高
-
多线程的缺点: 容易出错
注意:
很多多线程是模拟出来的,真正的多线程是指有多个 cpu,即多核,如服务器。
如 果是模拟出来的多线程,即 一个 cpu 的情况下,在同一个时间点,cpu 只能执行一个代码, 因为切换的很快,所以就有同时执行的错觉。
4.线程创建
-
1) 继承Thread ,重写run()方法,在方法内部定义线程体
-
2) 实现Runnable接口, 重写run() 方法 ,在方法内部定义线程体 ------------推荐
-
以上通过重写run方法定义线程体,不能抛出异常,也不能带出返回值
-
3) 实现Callable接口,重写call()方法,-->juc包下的
-
可以抛出异常,可以有返回值
public class ThreadDemo01 extends Thread{
//100
/*
* 线程体
*/
@Override
public void run() {
for(int i = 0;i<=20;i++) {
System.out.println("一遍敲代码......");
}
}
//主方法默认主线程
public static void main(String[] args) {
//创建线程
ThreadDemo01 th1 = new ThreadDemo01();
ThreadDemo01 th2 = new ThreadDemo01();
ThreadDemo01 th3 = new ThreadDemo01();
//开启线程 -->内部它会调用run()执行线程体
//th.start();
//th.run(); //方法的调用->只有主线程 先执行run()中的代码,执行完毕才继续执行main方法
th1.start();
th2.start();
th3.start();
for(int i = 0;i<=20;i++) {
System.out.println("一遍陪女朋友聊天......");
}
//th.start(); 也是开启多线程但是没有意义,先执行主线程,然后 在执行th线程
}
}
5.线程安全
-
什么情况下需要控制线程安全:
-
多个线程同时操作同一个份资源,才 有可能出现线程不安全问题
-
如何控制线程安全问题:
-
synchronized 关键字 控制线程安全–> 控制多个线程排队执行
-
用法:
-
同步方法 : 简单 效率较低
-
成员方法
-
静态方法
-
同步块
-
synchronized(this|类.class| 资源(成员属性)){ --> this 类 资源(成员属性)
-
要被你同步控制的代码区域–>有可能 会出现问题的代码区域
-
}
-
double check 双重检查提高效率
-
注意:
-
同步一定要同步不变的东西,会变的锁不住,对象地址肯定不会变
-
同步的代码范围过大,效率低,代码范围小,锁不住
-
静态方法时属于 类的,同步静态方法,相当于同步类.class -->(类的class对象每一个类只有一个,不用你创建,在类加载到内存中时就已经存在)
public class SynDemo01 {
public static void main(String[] args) {
new Thread(()->{
System.out.println(SingleTon.newInstance());
}).start();
new Thread(()->{
System.out.println(SingleTon.newInstance());
}).start();
new Thread(()->{
System.out.println(SingleTon.newInstance());
}).start();
}
}
//懒汉式
class SingleTon{
//2私有的静态的该类的引用
private static SingleTon singleTon;
//1.私有的构造器
private SingleTon(){}
//A B C
//3.公共的静态的访问方式,返回该类实例
public static SingleTon newInstance() {
System.out.println("-----------------");
if(singleTon == null) {
System.out.println("-----满足打印的话-----------");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//双重检查 double check -->提高效率
synchronized (SingleTon.class) { //同步类
if(singleTon == null) {
singleTon = new SingleTon();
}
}
}
return singleTon;
}