源码如下
public class HttpHeaders implements MultiValueMap<String, String>, Serializable {private final Map<String, List<String>> headers;public String getFirst(String headerName) {List<String> headerValues = (List)this.headers.get(headerName);return headerValues != null ? (String)headerValues.get(0) : null;}public void add(String headerName, String headerValue) {List<String> headerValues = (List)this.headers.get(headerName);if (headerValues == null) {headerValues = new LinkedList();this.headers.put(headerName, headerValues);}((List)headerValues).add(headerValue);}public void set(String headerName, String headerValue) {List<String> headerValues = new LinkedList();headerValues.add(headerValue);this.headers.put(headerName, headerValues);}
猜想
1.为了保证线程安全,可以保证可见性
但是找了一些文档,没有明确表示,可以保证这一点
可实现方案如下:
可见性的技术保障
1、Lock
2、synchronized
3、原子类
4、volatile
Lock和synchronized不用说,都是互斥锁,保障了共享资源在同一时刻只有一个线程可以访问,就不会出现可见性的问题。
volatile保障了一个变量修改以后马上写回主内存让其他线程可以看到,具体的分析后面再说。
至于原子类为什么也有可见性,因为他里面的value本身也是volatile修饰的。
顺便说下有序性
有序性的技术保障
1、synchronized
2、lock
3、volatile(一定程度的有序性)
synchronized和lock在同一时刻只能让一个线程执行同步方法,当然就是有序的了。
volatile的有序性是指写入修改后的volatile变量这个操作必定优先于 读取这个变量。
疑问
final修饰变量不是不可变吗,为什么后续还可以对他进行set add操作
智能搜索答案
分析一下答案,能对的上的
1.提高了性能
2.保证可见性
3.多线程安全
疑问解答
final修饰变量不是不可变吗,为什么后续还可以对他进行set add操作
下面这篇文章说的比较明白
JAVA中final关键字的作用_jvm final 修饰的 在编译阶段-CSDN博客
- 在上图中, 变量p指向了0003这块内存, 0003内存中保存的是对象p的句柄(存放对象p数据的内存地址), 这个句柄值是不能被修改的, 也就是变量p永远指向p对象. 但是p对象的数据是可以修改的.
- 不难看出final修饰变量的本质: final修饰的变量会指向一块固定的内存, 这块内存中的值不能改变.
- 引用类型变量所指向的对象之所以可以修改, 是因为引用变量不是直接指向对象的数据, 而是指向对象的引用的. 所以被final修饰的引用类型变量将永远指向一个固定的对象, 不能被修改; 对象的数据值可以被修改.
几个概念
引用数据类型 VS 基本数据类型
变量的引用(引用变量) (p)
对象的引用(就是内存地址)
对象的数据
内存:内存1:存的是地址;内存2:存的是数据(地址不可改,数据可改)