第二阶段:多线程设计模式详细介绍
2.Immutable 想破坏它也没办法
3.Guarded Suspension 要等我准备好哦
4.Balking 不需要的或就算了
5.Producer-Consumer 我来做,你来用
6.Read-Write Lock 大家想看就看吧,不过看的时候不能写哦
7.Thread-Per-Message 这个工作交给你了
8.Worker Thread 等到工作来,来了就工作
9.Future 先给你张提货单
10.Two-Phase Termination 快把玩具收拾好,去睡觉吧
11.Thread-Specific Storage 每个线程的保管箱
12.Active Object 接受异步消息的主动对象
1、You may not know the singleton design pattern
Single thread execution 能通过这座桥的,只有一个人
public class Singleton {
//饿汉式(静态常量)[可用] code easy,but can't lazy load
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
public class Singleton {
//饿汉式(静态代码块)[可用] can't lazy load
private static Singleton instance;
static{
instance = new Singleton();
}
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
public class Singleton {
//懒汉式(线程不安全)[不可用,多线程的情况下,一个线程进入if语句中,还未执行下面代码,另外一个线程同样进入,导致产生多个实例]
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(null == instance)
instance = new Singleton();
return instance;
}
}
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(null == instance) {
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if(null == instance) {
synchronized (Singleton.class) {
if(null == instance)
instance = new Singleton();
}
}
return Singleton.instance;
}
}
public class Singleton {
private Singleton() {}
private static class InstanceHolder{
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return InstanceHolder.instance;
}
}
public class Singleton {
private Singleton() {}
//枚举类型时线程安全的,并且它的构造函数只会被加载一次
private enum SingletonEnum{
INSTANCE;
private final Singleton instance;
SingletonEnum(){
instance = new Singleton();
}
public Singleton getInstance() {
return instance;
}
}
public static Singleton getInstance() {
return SingletonEnum.INSTANCE.getInstance();
}
}
2、WaitSet in synchronized monitor
wait set 线程的休息室,放到monitor中(锁)
WaitSet(线程休息室)
3、Cpu&Cpu Cache&Mian Memory&Data Bus&Cache
application-t1 写入CPU--->共享变量--->cache(CPU高速缓存一致性协议Inter的MESI)--->main memory
总线(数据总线,地址总线,控制总线)
cpu cache cache line
内存有2部分、RAM、ROM
CPU的寄存器、CPU指令
汇编、MOV、JMP、ADD
4、The volatile key word in deep
volatile可以保证内存的可见性,有顺性。不可以保证原子性
JMM的大致结构(java 内存模型)
缓存一致性协议
指令重排序
happens-before规则
并发编程的三大要素AVO(原子性(要么都成功,要么都失败),可见性,有序性)
volatile关键字的作用(可见性,有序性,不能保证原子性)
volatile的使用场景1)状态量标记2)屏障前后的一致性
volatile答疑
1、保证可见性:高速缓存的一致性协议
2、保证有序性:内存屏障
1、标志位
2、防止重排序(状态判断)
类一个共享资源ShareData
所有的基本类型赋值以及读取都是原子性的
宽子word 4 byte =int
i=1;
i=1+1;
cpu1->main memory->i->cache i+1 ->cache(2) ->main memory(2)
cpu2->main memory->i->cache i+1 ->cache(2) ->main memory(2)
1)给数据总线加锁
总线(数据总线,地址总线,控制总线)
LOCK
2)CPU高速缓存一致性协议
Inter的MESI
核心思想
1)当CPU写入数据的时候,如果发现该变量被共享(也就是说,在其他cpu中也存在该变量的副本),会发出一个信号,通知其他cpu该变量婚车无效
2)当其他cpu访问该变量的时候,重新到助内存进行获取
并发编程中三个重要的概念(AVO)
1)A原子性 一个操作或者多个操作,【要么都成功,要么都失败】,中间不能由于任何的因素中断
2)V可见性
3)O有序性(顺序性):重排序,只要求最终一致性
i=1;
flag = true;
重排序只要求最终一致性
volatile boolean init;
--------------Thread -1----------------
obj = createObj() 1;
init = true; 2;
--------------Thread -2----------------
whle(!init){
sleep();
}
useTheObj(obj);
-----------------------------------------
Java内存模型以及CPU缓存不一致的问题
1、原子性
对基本数据类型的变量读取和赋值是保证原子性的,要么都成功,哟么都失败,这些操作是不可被中断
i=10;
cache 10,memory 10;
a=10; 原子性
b=a; 不满足,1.read a;2.assign to b;
c++; 不满足,1.read c;2add;3assign to c;
c=c+a; 不满足,1.read c;2add;3assign to c;
2、可见性
使用volatile关键字保证可见性
3、有序性
happens-before relationship(重排序规则)
1)代码执行顺序,编写在前面的发送在编写在后面的
2)uolock必须发生在lock之后
3)volatile修饰的变量,对该变变量,先写后读
4)传递规则,操作A先于B,B先于C,那么A肯定先于C
5)线程的启动规则,start方法肯定先于线程run
6)线程的中断规则,interrupt这个动作,必须发生在捕获该动作之前
7)对象销毁规则,初始化必须发生在finalize之前
8)线程终结规则,所有的操作都发生在线程死亡之前那
try{
lock.lock();
}finally{
lock.unlock();
}
volatile关键字
一旦一个共享变量被volatile修饰,具备俩层语义
1)保证了不同线程间的可见性
2)禁止对其进行重排序,也就是保证了有序性
3)并未保证原子性
package com.topxin.designpattern.chapter3;
public class VolatileTest {
//volatile可以保证内存可见性,有顺性。不可以保证原子性
private /* volatile */ static int INIT_VALUE = 0;
private final static int MAX_LIMIT = 50;
public static void main(String[] args) {
new Thread(()->{
int localValue = INIT_VALUE;
while(localValue < MAX_LIMIT) {
if(localValue != INIT_VALUE) {
System.out.printf("The value update to [%d]\n",INIT_VALUE);
localValue = INIT_VALUE;
}
}
},"READER").start();
new Thread(()->{
int localValue = INIT_VALUE;
while(INIT_VALUE < MAX_LIMIT) {
System.out.printf("Update the value to [%d]\n",++localValue);
INIT_VALUE = localValue;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"UPDATER").start();
}
}
read from main memory INIT_VALUE->10
INIT_VALUE=10+1
INIT_VALUE=11
1)保证重排序的是不会把后面的指令放到屏障的前面,也不会把前面的放到后面
2)强制对缓存的修改操作立刻写入主存
3)如果是写操作,它会导致其他CPU中的缓存失效
volatile的使用场景
1)状态量标记
volatile boolean start = true;
while(start){}
void close(){start = false;}
2)屏障前后的一致性
总结
cpu的大致结构 application-t1 写入CPU--->共享变量--->cache(CPU高速缓存一致性协议Inter的MESI)--->main memory
总线(数据总线,地址总线,控制总线)
JMM的大致结构(java 内存模型)
缓存一致性协议
指令重排序、
happens-before规则
并发编程的三大要素AVO(原子性(要么都成功,要么都失败),可见性,有序性)
volatile关键字的作用(可见性,有序性,不能保证原子性)
volatile的使用场景1)状态量标记2)屏障前后的一致性
5、Java Class Loader
6、Observer to monitor the Thread lifecycle
Observerable/Subject主题/事件源(state) Observer事件源的被通知者
7、Single Thraded Execution design patten
READ | WRITE | |
READ | N | Y |
ERITE | Y | Y |
8、Immutable design pattern
不可变对象 final修饰 没有write 只有read
避免加锁,提高效率
不可变对象一定是线程安全的 里面的任务属性或者引用类型的属性都不能被修改
可变对象不一定是不安全的 StringBuffer
J2EE servlet 不是线程安全的
struts1.x Acton不是线程安全的
struts2.x Action是线程安全
9、Guarded Suspension
担保
被保护的,先放在队列里,之后一个个做
A在厨房做早餐
B是快递员,墙门,说你的快递来了,要求开门
Reqeust -> Tomcat httpServer ->doing
Request ->Tomcat httpServer
Queue
10、Balking design pattern
酒吧、服务生、轮值服务生,模拟word文件,ctrl+s保存,word自动保存
11、Producer-Consumer
12、Read-Write Lock design Pattern
waitset
wait
notifyAll
solution
BooleanLock
syschronized
->Data
read
write
1. read other thread wail enter to the waitset
2. read write 锁分离
concern conflict
1.read read 并行化
2.read write 不允许
3.write write 不允许
ReadWriteLock design pattern
Reader-Writer design pattern
13、Thread-Per-Message Design Pattern
线程池
14、Worker Thread Design Pattern
屏蔽了worker
15、Future
票据,结果有了过一会去拿,留下地址
Future ->代表的是未来的一个凭据
FutureTask ->将你的调用逻辑进行隔离
FutureService ->桥接 Future 和 FutureTask
16、Two-Phase Termination Design Pattern
2个阶段终结
17、The Thread-Specific Storage
线程保险箱,高效,线程安全,用途广,(可以解决上下文传值的问题)
线程保险箱,上下文,Map,用线程作为key
ThreadLocal 始终以当前线程作为key值
private static final ThreadLocal<Context> threadLocal = new ThreadLocal<Context>() {
@Override
protected Context initialValue() {
return new Context();
}
};
总结
invoke一个方法
Future 提货单,注入一个函数,线程间的通讯
Suspenion 先挂起来,有时间了一个一个做,线程间的通讯
example
balking 放弃
18、Active Objects
19、Count Down Design Pattern
所有东西都完成在来,用通知方式实现了LocalThread