目录
多线程基础知识要点

案例一:单例模式
是一种设计模式
软件设计需要框架,这是硬性的规定;设计模式是软性的规定。遵循好设计模式,代码的下限就被兜住了
单例 = 单个实例(对象)
某个类在一个进程中只应该创建出一个实例(原则上不应该有多个)
使用单例模式可以对代码进行一个更严格的校验和检查
实现单例模式~
饿汉模式
第1步:
class Singleton{
private static Singleton instance = new Singleton();
}
这里的static指的是类属性,而instance就是Singleton类对象持有的属性
每个类的类对象只存在一个,类对象中的static属性自然只有一个了
因此instance指向的这个对象,就是唯一的对象
第2步:

其他代码要想使用这个类的实例就需要通过这个方法来进行获取。不应该在其他代码钟重新new这个对象,而是使用这个方法获取到现成的对象(已经创建好的对象)
第3步:奇淫巧计

这里直接把Singleton给private了,其他代码根本没办法new

此时,无论你创建多少个对象,这些对象其实都是一样的

饿汉模式下,实例是在类加载的时候就创建了,创建时机非常早,相当于程序一启动,实例就创建了。“饿汉”形容“创建实例非常迫切,非常早”
欸!但是用非常规手段:反射就可以打破上述约定。我们可以用枚举方法来创建单例模式
懒汉模式
创建实例的时机更晚,只到第一次使用的时候才会创建实例
“懒”的思想
比如有一个非常大的文件(10GB),有一个编辑器,使用编辑器打开这个文件,如果是按照饿汉的方式,编辑器就要把这10GB先加载到内存里,然后再统一地展示。加载太多数据,用户还得一点点看,没办法一下看那么多
如果按照懒汉的方式,编辑器就会制度取一小部分数据,把这部分数据先展示出来,随着用户翻页之类的操作再继续读后面的数据。这样效率可以提高
class SingletonLazy{
private static SingletonLazy instance = null;//先初始化为null,不是立即初始化
public static SingletonLazy getInstance(){
if (instance == null){
instance = new SingletonLazy();//首次调用getInstance才会创建出一个实例
}
return instance;
}
private SingletonLazy(){}
}
思考:懒汉模式是否线程安全?
这样t1 new了一个对象,t2也new了一个对象,就会出现bug
所以,懒汉模式不是线程安全的
那怎么改成线程安全的呢?
1.加锁,synchronized
2.把if和new两个操作打包成一个原子

仍然是t1和t2两个线程,t1先执行加锁代码,t2就被阻塞了,要等待t1释放锁才能继续执行
而t1把instance修改之后,t2的if条件就不成立了,直接就返回了

emm,这段代码还不够完美...
在多线程里面,当第一个线程加了锁,后面的线程再调用getInstance就是纯粹的读操作了,也就不会有线程问题了。那么没有线程的代码每次执行都要加锁和解锁,每次都会产生阻塞,效率巨低!
所以在synchronized外边还得再套一层if,判定代码是否要加锁。仍然将instance是否为空作为判断条件

第一个if判定是否加锁
第二个if判定是否要创建对象
🆗上面的代码还有一点问题
涉及到指令重排序引起的线程安全问题
指令重排序是指调整原有代码的执行顺序,保证逻辑不变的前提下提高程序的效率
为什么调整代码执行顺序可以提高程序效率?
比如我们去超市买东西,我们需要买黄瓜,胡萝卜,西红柿,土豆。我们就有很多种去不同摊位的路径选择,每种选择的最终总购买时间不一样。这就相当于程序的效率。
![]()
这行代码可以分成三个大步骤
1.申请一段内存空间
2.在这个内存上调用构造方法,创建出这个实例
3.把这个内存地址赋给Instance引用变量
假设有t1和t2两个线程
t1线程按照1 3 2的执行顺序,就会出现问题

解决上述问题核心思路:volatile
volatile有两个功能:
1)保证内存可见性,每次访问变量必须要重新读取内存,而不会优化到寄存器/缓存中
2)禁止指令重排序,针对这个volatile修饰的变量的读写操作的相关指令,是不能被重排序的
![]()
这样修改之后,针对instance变量的读写操作就不会出现重排序
案例二:阻塞队列
特点:1.线程安全;2.阻塞
如果一个已经满了的队列进行入队列,此时入队列操作就会阻塞,一直阻塞到队列不满之后
如果一个已经空的队列进行出队列,出队列操作就会阻塞,一直阻塞到队列有元素为止
可以实现生产者消费者模型
这个模型可以更好地解耦合(把代码的耦合程度从高降低)
实际开发中,往往会用到分布式系统,服务器整个功能不是由一个服务器完成的,而是每个服务器负责一部分功能。通过服务器之间的网络通信,最终完成整个功能

在这个案例中,A和B,C之间的耦合性比较强,一旦B或者C挂了一个,A也就跟着挂了
如果引入生产者消费者模型

这个阻塞队列不是简单的数据结构,而是基于这个数据结构实现的服务器程序,又被部署到单独的主机上
削峰填谷

为啥当请求多了的时候,服务器就容易挂?

最低0.47元/天 解锁文章
3945

被折叠的 条评论
为什么被折叠?



