• 1. java集合深入理解

    • 1.1 迭代器的快速失败机制 fast-fail
    • 1.2 collection 集合
    • 1.3 List集合
      • 1.3.1 ArrayList
      • 1.3.2 LinkList
  • 2. Map 综述
    • 2.1 彻头彻尾理解 HashMap
    • 2.2彻头彻尾理解 LinkedHashMap
    • 2.3 彻头彻尾理解 ConcurrentHashMap
    • 2.4 彻头彻尾理解 HashTable
  • 3. java面试锦集
  • 4. String
    • 1.String
    • 2.StringBuilder
    • 3. StringBuffer
    • 4. 总结
  • 5. 泛型
  • 6.注解
  • 7.java io
    • 7.1 File
    • 7.2 字节流字符流
    • 7.3 Pushback流
    • 7.4 RandomAccessFile
    • 7.5 序列化
      • a.序列化算法
      • b.反序列化创建对象
      • c.自定义序列化
      • d.注意事项
  • 8 线程
    • 8.1 创建线程的三种方式
    • 8.2 Daemon线程
    • 8.3 interrupt的理解
    • 8.4 synchronized volatile
    • 8.5 wait notify
    • 4. Lock
    • 5. 并发容器
    • 6. 偏向锁,轻量锁,重量级锁
    • 7 内存屏障
    • 8 可重入锁解析 ReentrantLock
      • 1.加锁过程
      • 2.解锁过程
  • 9 final
  • 10 深拷贝VS浅拷贝

1. java集合深入理解

https://blog.csdn.net/u011240877/article/category/6447444
http://www.cnblogs.com/skywang12345/p/3323085.html

1.1 迭代器的快速失败机制 fast-fail

https://blog.csdn.net/chewbee/article/details/78314661
1. 是java集合的一种错误检测机制
2. 防止一个线程在对集合进行迭代时候,另一个线程在结构上对集合进行修改,不是单纯的修改集合元素值

1.2 collection 集合

https://blog.csdn.net/justloveyou_/article/details/52948661

1.3 List集合

https://blog.csdn.net/justloveyou_/article/details/52955619

1.3.1 ArrayList

a. 内部数据结构

  private transient Object[] elementData;                 // 瞬时域private int size;

b. 扩容操作 这是一个public 函数,默认每次扩容是 1.5倍 + 1

// 调整数组容量public void ensureCapacity(int minCapacity) {modCount++;int oldCapacity = elementData.length;if (minCapacity > oldCapacity) {Object oldData[] = elementData;int newCapacity = (oldCapacity * 3)/2 + 1;if (newCapacity < minCapacity)newCapacity = minCapacity;// minCapacity is usually close to size, so this is a win:// 最终会调用 System.ArrayCopy() 这是一个内存块拷贝函数elementData = Arrays.copyOf(elementData, newCapacity);}}

c. 序列化 虽然内部数据结构一个是瞬态数据和一个基本数据类型 ,但是通过自定义的readObject()/writeObject()

private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException{// Write out element count, and any hidden stuffint expectedModCount = modCount;s.defaultWriteObject();// Write out size as capacity for behavioural compatibility with clone()s.writeInt(size);// Write out all elements in the proper order.for (int i=0; i<size; i++) {s.writeObject(elementData[i]);}if (modCount != expectedModCount) {throw new ConcurrentModificationException();}}private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {elementData = EMPTY_ELEMENTDATA;// Read in size, and any hidden stuffs.defaultReadObject();// Read in capacitys.readInt(); // ignoredif (size > 0) {// be like clone(), allocate array based upon size not capacityint capacity = calculateCapacity(elementData, size);SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);ensureCapacityInternal(size);Object[] a = elementData;// Read in all elements in the proper order.for (int i=0; i<size; i++) {a[i] = s.readObject();}}}

d. ArrayList 允许值为null

// 移除此列表中 “首次” 出现的指定元素(如果存在)。这是因为 ArrayList 中允许存放重复的元素。  public boolean remove(Object o) {  // 由于ArrayList中允许存放null,因此下面通过两种情况来分别处理。  if (o == null) {  for (int index = 0; index < size; index++)  if (elementData[index] == null) {  // 类似remove(int index),移除列表中指定位置上的元素。  fastRemove(index);  return true;  }  } else {  for (int index = 0; index < size; index++)  if (o.equals(elementData[index])) {  fastRemove(index);  return true;  }  }  return false;  }
}

1.3.2 LinkList

a. 头结点不存放任何数据
b. 新增元素放在链表尾部
c. 只能遍历访问,不能随机访问

2. Map 综述

https://blog.csdn.net/justloveyou_/

2.1 彻头彻尾理解 HashMap

https://blog.csdn.net/justloveyou_/article/details/62893086

初始容量: 桶的数量
负载因子: 扩容阈值=负载因子 * 初始容量

  1. 有两个重要的数据: 容量(默认是16),负载因子(默认是0.75)
  2. 使用数组链表的结构来存储
  3. put操作
  4. get操作
  5. resize扩容操作 多线程的情况下出现死循环
  6. 非线程安全的
  7. 迭代器的快速失败机制fast-fail机制

    在使用迭代器遍历Hashmap的过程中,别的线程不允许修改hashmap,要不然就会出现快速失败,内部是通过modCount计算器来实现的.

  8. 多线程并发HashMap,写操作导致扩容

    1. 内部的链表产生死循环 cpu100%
    2. 获取null
    3. 元素丢失
      https://www.cnblogs.com/dongguacai/p/5599100.html
      https://blog.csdn.net/u013668852/article/details/77141842
 /*** Associates the specified value with the specified key in this map.* If the map previously contained a mapping for the key, the old* value is replaced.** @param key key with which the specified value is to be associated* @param value value to be associated with the specified key* @return the previous value associated with key, or null if there was no mapping for key.*  Note that a null return can also indicate that the map previously associated null with key.*/public V put(K key, V value) {//当key为null时,调用putForNullKey方法,并将该键值对保存到table的第一个位置 if (key == null)return putForNullKey(value); //根据key的hashCode计算hash值int hash = hash(key.hashCode());             //  ------- (1)//计算该键值对在数组中的存储位置(哪个桶)int i = indexFor(hash, table.length);              // ------- (2)//在table的第i个桶上进行迭代,寻找 key 保存的位置for (Entry<K,V> e = table[i]; e != null; e = e.next) {      // ------- (3)Object k;//判断该条链上是否存在hash值相同且key值相等的映射,若存在,则直接覆盖 value,并返回旧valueif (e.hash == hash && ((k = e.key) == key || key.equals(k))) {V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;    // 返回旧值}}modCount++; //修改次数增加1,快速失败机制//原HashMap中无该映射,将该添加至该链的链头addEntry(hash, key, value, i);            return null;}

2.2彻头彻尾理解 LinkedHashMap

https://blog.csdn.net/justloveyou_/article/details/71713781


0. 增加属性: 链表头节点header , 标志位accessOrder,默认是保持插入顺序
1. 在HashMap的基础上增加双向链表
2. 默认是保持插入顺序
3. LUR算法(最近最少使用)
1. HashMap与LinkHashMap 的get/set方法会访问accessOrder() ,但是HashMap的accessOrder()是空操作
2. LinkHashMap的accessOrder(),如果对应的accessOrder设置为true recordAccess()函数在访问内部节点的时候就会把访问节点放到队列的尾部,并删除当前节点

新增节点

/*** This override alters behavior of superclass put method. It causes newly* allocated entry to get inserted at the end of the linked list and* removes the eldest entry if appropriate.** LinkedHashMap中的addEntry方法*/void addEntry(int hash, K key, V value, int bucketIndex) {   //创建新的Entry,并插入到LinkedHashMap中  createEntry(hash, key, value, bucketIndex);  // 重写了HashMap中的createEntry方法//双向链表的第一个有效节点(header后的那个节点)为最近最少使用的节点,这是用来支持LRU算法的Entry<K,V> eldest = header.after;  //如果有必要,则删除掉该近期最少使用的节点,  //这要看对removeEldestEntry的覆写,由于默认为false,因此默认是不做任何处理的。  if (removeEldestEntry(eldest)) {  removeEntryForKey(eldest.key);  } else {  //扩容到原来的2倍  if (size >= threshold)  resize(2 * table.length);  }  } void createEntry(int hash, K key, V value, int bucketIndex) { // 向哈希表中插入Entry,这点与HashMap中相同 //创建新的Entry并将其链入到数组对应桶的链表的头结点处, HashMap.Entry<K,V> old = table[bucketIndex];  Entry<K,V> e = new Entry<K,V>(hash, key, value, old);  table[bucketIndex] = e;     //在每次向哈希表插入Entry的同时,都会将其插入到双向链表的尾部,  //这样就按照Entry插入LinkedHashMap的先后顺序来迭代元素(LinkedHashMap根据双向链表重写了迭代器)//同时,新put进来的Entry是最近访问的Entry,把其放在链表末尾 ,也符合LRU算法的实现  e.addBefore(header);  size++;  }

recordAccess() HashMap是一个空函数,LinkHashMap如下所示:

     void recordAccess(HashMap<K,V> m) {  LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;  //如果链表中元素按照访问顺序排序,则将当前访问的Entry移到双向循环链表的尾部,  //如果是按照插入的先后顺序排序,则不做任何事情。  if (lm.accessOrder) {  lm.modCount++;  //移除当前访问的Entry  remove();  //将当前访问的Entry插入到链表的尾部  addBefore(lm.header);  }  }
  1. 使用LinkHashMap实现LRU算法
public class LRU<K,V> extends LinkedHashMap<K, V> {private static final long serialVersionUID = 1L;public LRU(int initialCapacity,float loadFactor, boolean accessOrder) {super(initialCapacity, loadFactor, accessOrder);}/* LinkHashMap中的实现就是单纯的返回一个false,也就是不删除节点protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {return false;}
*/@Overrideprotected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {// TODO Auto-generated method stubif(size() > 6){return true;}return false;}public static void main(String[] args) {LRU<Character, Integer> lru = new LRU<Character, Integer>(16, 0.75f, true);String s = "abcdefghijkl";for (int i = 0; i < s.length(); i++) {lru.put(s.charAt(i), i);}System.out.println("LRU中key为h的Entry的值为: " + lru.get('h'));System.out.println("LRU的大小 :" + lru.size());System.out.println("LRU :" + lru);}
}

2.3 彻头彻尾理解 ConcurrentHashMap

https://blog.csdn.net/justloveyou_/article/details/72783008

a. segment继承ReentrantLock ,使得对象具备了锁的功能
b. 初始容量,负载因子,并发级别 三个重要参数 . 默认值分别为16 , 0.75 , 16

构造函数 : 根据初始容量,并发级别,确定 多少各segment 以及每个segment多少个桶

 public ConcurrentHashMap(int initialCapacity,  float loadFactor, int concurrencyLevel) {if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)throw new IllegalArgumentException();if (concurrencyLevel > MAX_SEGMENTS)              concurrencyLevel = MAX_SEGMENTS;// Find power-of-two sizes best matching argumentsint sshift = 0;            // 大小为 lg(ssize) int ssize = 1;            // 段的数目,segments数组的大小(2的幂次方)// 并发级别可能不是2的幂次方 ,转换一下// 假设并发级别是5,那么就会分为8段while (ssize < concurrencyLevel) {++sshift; ssize <<= 1;}segmentShift = 32 - sshift;      // 用于定位段segmentMask = ssize - 1;      // 用于定位段// this.segments = Segment.newArray(ssize);   // 创建segments数组if (initialCapacity > MAXIMUM_CAPACITY)initialCapacity = MAXIMUM_CAPACITY;int c = initialCapacity / ssize;    // 总的桶数/总的段数 = 平均每个段中的桶数目 ,但是不是 2 幂次方if (c * ssize < initialCapacity)++c;int cap = 1;     // 每个段所拥有的桶的数目(2的幂次方)while (cap < c)cap <<= 1;for (int i = 0; i < this.segments.length; ++i)      // 初始化segments数组this.segments[i] = new Segment<K,V>(cap, loadFactor);}

c. put操作

d. get操作

// Segment 类V get(Object key, int hash) {if (count != 0) {            // read-volatile,首先读 count 变量HashEntry<K,V> e = getFirst(hash);   // 获取桶中链表头结点while (e != null) {if (e.hash == hash && key.equals(e.key)) {    // 查找链中是否存在指定Key的键值对V v = e.value;if (v != null)  // 如果读到value域不为 null,直接返回return v;   // 如果读到value域为null,说明发生了重排序,加锁后重新读取return readValueUnderLock(e); // recheck}e = e.next;}}return null;  // 如果不存在,直接返回null
}

e. rehash操作
f. size() 统计大小操作

  1. 不加锁重试2次,每次去统计segment中的数量的时候,计入modCount的大小, 所有的段统计完成,去比较一下每个段中的modCount是否产生变化
  2. 如果产生变化,那么就对所有的段加锁,再次统计一下

g. 与JDK1.8实现的ConcurrentHashMap对比
https://blog.csdn.net/fouy_yun/article/details/77816587
1. 取消了分段
2. 链表长度默认超过8 ,变成红黑树

put操作 部分添加操作加锁

1. 若table[]未创建,则初始化。
2. 当table[i]后面无节点时,直接创建Node(无锁操作)。  cas原子操作
3. 如果当前正在扩容,则帮助扩容并返回最新table[]。
4. 然后在链表或者红黑树中追加节点。 锁住当前table[i]
5. 最后还回去判断是否到达阀值,如到达变为红黑树结构。

get操作 整个过程都没有加锁

1. 首先定位到table[]中的i。
2. 若table[i]存在,则继续查找。
3. 首先比较链表头部,如果是则返回。
4. 然后如果为红黑树,查找树。
5. 最后再循环链表查找。

2.4 彻头彻尾理解 HashTable

https://blog.csdn.net/justloveyou_/article/details/72862373

  1. Hashtable不同于HashMap,前者既不允许key为null,也不允许value为null;
  2. HashMap中用于定位桶位的Key的hash的计算过程要比Hashtable复杂一点,没有Hashtable如此简单、直接;
  3. 在HashMap的插入K/V对的过程中,总是先插入后检查是否需要扩容;而Hashtable则是先检查是否需要扩容后插入;
  4. Hashtable不同于HashMap,前者的put操作是线程安全的

    put操作 :

    1. 方法同步
    2. 不允许空value
    3. 没有对key做出null处理,暗示key不能为null
    4. 计算桶的位置使用的是取模运算,也不是HashMap的&运算,也就是说HashTable的初始容量没有什么要求
    5. 先判断是否需要扩容,再插入节点
 public synchronized V put(K key, V value) {     // 加锁同步,保证Hashtable的线程安全性// Make sure the value is not nullif (value == null) {      // 不同于HashMap,Hashtable不允许空的valuethrow new NullPointerException();}// Makes sure the key is not already in the hashtable.Entry tab[] = table;int hash = key.hashCode();   // key 的哈希值,同时也暗示Hashtable不同于HashMap,其不允许空的keyint index = (hash & 0x7FFFFFFF) % tab.length;   // 取余计算节点存放桶位,0x7FFFFFFF 是最大的int型数的二进制表示// 先查找Hashtable上述桶位中是否包含具有相同Key的K/V对for (Entry<K, V> e = tab[index]; e != null; e = e.next) {if ((e.hash == hash) && e.key.equals(key)) {V old = e.value;e.value = value;return old;}}// 向Hashtable中插入目标K/V对modCount++;     // 发生结构性改变,modCount加1if (count >= threshold) {    //在插入目标K/V对前,先检查是否需要扩容(不同于HashMap的插入后检查是否需要扩容) // Rehash the table if the threshold is exceededrehash();tab = table;index = (hash & 0x7FFFFFFF) % tab.length;   // 扩容后,重新计算K/V对插入的桶位}// Creates the new entry.Entry<K, V> e = tab[index];tab[index] = new Entry<K, V>(hash, key, value, e); // 将K/V对链入对应桶中链表,并成为头结点count++;     // Hashtable中Entry数目加1return null;}

get操作

  1. 同步方法
  2. 取模的方式定位桶位置
  3. 在链表中查找指定的key ,没找到返回null
public synchronized V get(Object key) {    // 不同于HashMap,Hashtable的读取操作是同步的Entry tab[] = table;int hash = key.hashCode();   int index = (hash & 0x7FFFFFFF) % tab.length;   // 定位K/V对的桶位for (Entry<K, V> e = tab[index]; e != null; e = e.next) {   // 在特定桶中依次查找指定Key的K/V对if ((e.hash == hash) && e.key.equals(key)) {return e.value;       }}return null;   // 查找失败}

3. java面试锦集

https://blog.csdn.net/justloveyou_/article/details/78653660
https://blog.csdn.net/justloveyou_/article/details/78653929
https://blog.csdn.net/justloveyou_/article/details/78313167

4. String

https://blog.csdn.net/justloveyou_/article/details/52556427
https://blog.csdn.net/justloveyou_/article/details/60983034

1.String

对String的一般认识

  1. 类使用了final修饰,不能被继承
  2. 内部字段也被final修饰,初始化就不能再次修改
  3. String是一个不可变类,线程安全
  4. 内部使用的是char[]来表示

编译期间就会把字面字符串放到字符串常量池 字符串拼接操作

  1. 字符串字面量拼接,标量替换
  2. 字符串引用拼接 ,还是会调用StringBuilder.append toString返回一个String对象

引用拼接的本质:

String s4 = s1 + s2 + s3;
====>
String s4 = (new StringBuilder(String.valueOf(s1))).append(s2).append(s3).toString();

2.StringBuilder

  1. 不是线程安全的类
  2. 是单线程下替换StringBuffer的一个类

3. StringBuffer

  1. 是一个线程安全的类

4. 总结

  1. 使用字面值形式创建字符串时,不一定会创建对象,但其引用一定指向位于字符串常量池的某个对象;
  2. 使用 new String(“…”)方式创建字符串时,一定会创建对象,甚至可能会同时创建两个对象(一个位于字符串常量池中,一个位于堆中);
  3. String 对象是不可变的,对String 对象的任何改变都会导致一个新的 String 对象的产生,而不会影响到原String 对象;
  4. StringBuilder 与 StringBuffer 具有共同的父类,具有相同的API,分别适用于单线程和多线程环境下。特别地,在单线程环境下,StringBuilder 是 StringBuffer 的替代品,前者效率相对较高;

5. 泛型

https://blog.csdn.net/s10461/article/details/53941091
泛型遇上多态
https://blog.csdn.net/lonelyroamer/article/details/7868820

6.注解

https://blog.csdn.net/briblue/article/details/73824058
https://www.cnblogs.com/Qian123/p/5256084.html

7.java io

7.1 File

7.2 字节流字符流

7.3 Pushback流

7.4 RandomAccessFile

7.5 序列化

自定义readObject函数的调用过程
https://blog.csdn.net/xiaoanian/article/details/9064635
https://www.cnblogs.com/yoohot/p/6019767.html

a.序列化算法

  1. 所有的对象都有一个序列化编号
  2. 检查对象是否已经被序列化
  3. 如果已经序列化,那么只输出序列化编号

note: 注意可变对象的序列化

b.反序列化创建对象

  1. 获取反序列化对象的元数据(Class文件) ——> 该类还没有被加载,那就执行类加载机制
  2. 在内存中创建内存空间
  3. 直接内存赋值
  4. 不需要调用构造函数

c.自定义序列化

  1. 实现Serializable接口,该接口就是一个标记,内部没有任何东西
  2. 实现Externalizable接口

d.注意事项

  1. 父类实现了序列化,子类自动实现序列化
  2. 基类没有实现序列化
    1. 如果 存在无参构造函数,那么序列化过程中不会报错,但是不会保存实例变量值
    2. 如果不存在无参构造函数,那么序列化过程中直接报错
  3. transient修饰的变量不参与序列化,类变量也不参与序列化

8 线程

8.1 创建线程的三种方式

  1. 继承Thread
  2. 实现Runnable接口
  3. 实现Callable接口

8.2 Daemon线程

  1. 需要在线程启动之前设置为后台线程,否则线程启动之后,线程状态是Runnable,而在setDaemon函数中会判断线程状态是不是new状态,不是就报错了
  2. 所有的前台线程退出了,那么后台线程也就退出了
  3. Daemon线程中再次创建线程也是Daemon线程

8.3 interrupt的理解

https://www.ibm.com/developerworks/cn/java/j-jtp05236.html
https://www.cnblogs.com/timlearn/p/4008783.html
1. java中断是一种协调机制
2. 线程对象调用interrupt函数向线程发送一个中断信号
3. 在线程内部,如果线程处于阻塞,那么就会抛出InterruptException异常;如果处于运行状态,那么就会设置一下该线程的中断状态为真
4. isInterrupted()函数返回线程现在是不是中断状态,但是不会影响中断状态
5. interrupted()静态函数,会重置中断状态

8.4 synchronized volatile

  1. volatile

    1. 保证各线程的可见性,但是不保证原子性.线程的工作内存马上同步到主内存中
    2. 禁止指令重排序
    3. 轻量级锁
      https://www.cnblogs.com/wq3435/p/6220751.html
      https://blog.csdn.net/justloveyou_/article/details/53672005
  2. synchronized可以保证

8.5 wait notify

https://www.cnblogs.com/hapjin/p/5492645.html
线程状态转移
https://blog.csdn.net/pange1991/article/details/53860651
问题1: 为什么会假唤醒?
问题2: 为什么需要需要同步?

synchronized(object){// 使用while防止假唤醒while(条件不满足){object.wait();}//逻辑处理;
}synchronized(object){//改变条件object.notifyAll();
}
  1. 对象的wait notify方法必须在同步快内部,也就是说需要获取对象锁才可以调用执行
  2. notify()执行,出了同步快,那么就会唤醒该对象等待队列上的线程,进入同步队列
  3. wait()执行,放弃cpu资源,释放锁,线程放进等待队列中,等待唤醒

4. Lock

5. 并发容器

6. 偏向锁,轻量锁,重量级锁

7 内存屏障

http://ifeve.com/disruptor-memory-barrier/

8 可重入锁解析 ReentrantLock

http://www.cnblogs.com/xrq730/p/4979021.html
https://blog.csdn.net/lsgqjh/article/details/63685058

1.加锁过程

final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) { //如果没有线程获取锁,则当前线程CAS获取锁。并设置自己为当前锁的独占线程if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {// 如果存在锁竞争,判断获取锁的线程是否是当前线程, 如果是 那么根据可重入的含义, 使当前state+1;int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}如果不是当前线程,则不能获取同步状态return false;    }
  1. 获取volatile修饰的state值
  2. 如果state的值为0,说明还没有线程持有锁
    1. 使用CAS操作设置state的值
    2. 设置当前线程持有锁
  3. state不为0,说明当前有线程持有该锁,那么判断是不是当前线程想重入

    1. 如果是,重新设置state的值
    2. 如果不是,获取锁失败

    2.解锁过程

    protected final boolean tryRelease(int releases) {int c = getState() - releases;//  只有获得锁的线程自己才能释放锁if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;if (c == 0) {//c==0说明已经无锁free = true;setExclusiveOwnerThread(null);}setState(c);//否则更新state为state-1, 也就是加锁多少次,就得释放多少次, lock unlock配对使用。return free;}
    1. 当前线程不持有锁,解锁异常抛出
    2. 获取state值
      1. 如果state的值为0了,那么说明解锁完就没有那个对象持有该锁了,需要设置锁没有持有任何线程
      2. 重新设置state

9 final

https://www.cnblogs.com/senlinyang/p/7875468.html
1. 写final域的重排序规则:禁止把final域的写重排序到构造函数之外——>对象的引用在任意线程可见之前,final域一定是已经正确初始化过的
通过下面2种方式保证
a. JMM禁止编译器把final域写重排序到构造函数之外
b. 编译器会在final域的写之后,构造函数return之前,插入一个StoreStore内存屏障

2. 读final域的重排序规则: 初次读对象引用和初次读对象包含的final域两个操作之间禁止重排序,编译器会在两个操作之间插入LoadLoad内存屏障——–>在读一个对象的final域之前,一定会先读取包含这个final域的对象的引用
3. final域是一个引用类型,final域对象内部成员的初始化和使用对象之间禁止重排序
final域可以给我们一下保证: 只要对象正确的构造,那么不需要同步,任意线程都可以看到final域在构造函数中初始化值

10 深拷贝VS浅拷贝

java 学习资料总结相关推荐

  1. JAVA学习资料整理

    今天偶然间发现之前一个群里发过的一篇关于JAVA学习资料的东西.本着服务大众的精神,搬来了博客园: <JAVA编程思想>第四版(英文原版) 下载地址:http://115.com/file ...

  2. 不得不知道的一些Java学习资料

    Java学习资料 下面是我们花费大量精力整理出来的 Java 学习资料,这套 Java 学习资料由 Java 书籍和 Java 视频两大部分组成,我们会根据 Java 学习路线,按照由浅至深的顺序进行 ...

  3. 2020最新java学习资料,全套源码无加密网盘下载

    点击上方蓝字关注我们! 前言--------2020最新java学习资料完整版,全套源码无加密网盘下载 最近小编整理了三套java的学习资料(视频+资料+源码),无加密: 1.2020java会员版 ...

  4. Java学习资料汇总(JavaSE+JavaEE+数据库+框架+笔试题+面试题)

    在写下这篇文章的时候,我还在找工作.理解每一个真正对编程感兴趣的小伙伴的转行不易,于是就把自己这几个月搜索到的学习资料一一分享给大家. 3.数据库 MySQL5.7 Reference Manual ...

  5. [Java学习资料] [成长之路]

    [背景] 网上学习资料千千万万,成长之路千千万万,各取所需 JAVA基础 网站 https://www.runoob.com/java/java-tutorial.html https://www.w ...

  6. 优秀java学习资料大全

    http://www-900.ibm.com/developerWorks/cn/java/index.shtml  IBM的JAVA专题--永远的蓝色巨人    http://www.huihoo. ...

  7. 分享优秀java学习资料大全

    http://www-900.ibm.com/developerWorks/cn/java/index.shtml  IBM的JAVA专题--永远的蓝色巨人   http://www.huihoo.c ...

  8. 初学java 学习资料整理

    前言 学习java已经有四天时间了,目前学习完了包括基础语法.面向对象.异常处理等java基础,但是在熟练程度以及工具使用方面都还需要继续加强.java的生态果然明显更好,高质量的学习资料也确实不少. ...

  9. Java学习资料汇总(吐血分享)----持续更新中

    java学习攻略: 1.javase  html  css  javascript 历经5年锤炼(史上最适合初学者入门的Java基础视频) Java基础教程(java入门学习第一免费视频下载) Jav ...

  10. 最新Java学习资料与思维导图分享,免费领取!

    很多学 Java 的同学时常会发现,在校时学了一套东西,到大公司面试时又是另一套东西. 其实,归根结底,还是本人缺少真正的实战经验,这里整理了一份系统化学习的思维导图(完整版文末领取),大家查漏补缺, ...

最新文章

  1. 皮一皮:这是为什么呢???
  2. 浅谈中大型企业CMDB的建设
  3. Linux 下的tar常用命令及操作
  4. Existing lock /var/run/yum.pid: another copy is running as pid
  5. java中抽象类与接口的不同之处
  6. switch case的天坑
  7. 反直觉的一个游戏 - 三门问题 (Monty Hall problem)
  8. 问题 1125: 【C语言训练】委派任务*【最优解】
  9. 打印所有的水仙花数---初学c语言
  10. 微信小程序纯前端生成海报并保存本地
  11. 第三方应用调用高德地图
  12. 1Mbps带宽到底能够达到什么效果,看看下面的介绍就懂了。
  13. 昂达v80 plus linux,昂达(ONDA)V80 Plus平板电脑整体性能评测-ZOL中关村在线
  14. 杂-格签名中常见数字的意义
  15. Minecraft 1.18.1、1.18.2模组开发 17.自定义盾牌(shield)
  16. js插件动态加载js、css解决方案
  17. 蚂蚁金服原副总裁漆远加盟复旦大学,任人工智能院长
  18. 你应该考这些证书,特别是在校生
  19. 小米3基于android,小米手机3评测 最大最快的小米3详细评测图文介绍
  20. AFW短信防火墙 v1.0 beta 发布

热门文章

  1. 《电子元器件的可靠性》——3.3节可靠性筛选试验
  2. docker安装网易云音乐(yesplaymusic)
  3. dcs world f15c教学_烟台TSXP57353M【四点零自动化】DCS系统
  4. SetTimer函数
  5. java实现医嘱管理系统_Chis5.0医嘱管理系统业务使用手册
  6. 华为顶级黑客整理的399本编程电子书,整整16个G,你想学的都有
  7. 一周新闻纵览:谷歌浏览器信息泄露,出卖个人信息获利终落网,严查App偷窥乱象
  8. java 语言的介绍
  9. DVB 数字电视基础知识
  10. OGG-01433 Oracle GoldenGate Capture for Oracle, EXXX.prm: Failed to validate table <SCHEMANAME.TABLE