弱引用(WeakReference)的特性是:當gc線程發現某個對象只有弱引用指向它,那麼就會將其銷燬並回收內存。WeakReference也會被加入到引用隊列queue中。 java
它的特殊之處在於 WeakHashMap 裏的entry可能會被GC自動刪除,即便程序員沒有調用remove()或者clear()方法。程序員
可能發生以下狀況:api
WeekHashMap 的這個特色特別適用於須要緩存的場景。數組
GC判斷某個對象是否可被回收的依據是,是否有有效的引用指向該對象。緩存
這裏的「有效引用」並不包括弱引用。也就是說,雖然弱引用能夠用來訪問對象。安全
將一對key, value放入到 WeakHashMap 裏並不能避免該key對應的內存區域被GC回收。數據結構
既然有 WeekHashMap,是否有 WeekHashSet 呢?答案是沒有,不過Java Collections工具類給出瞭解決方案,多線程
// 將WeakHashMap包裝成一個Set框架
Set<Object> weakHashSet = Collections.newSetFromMap(new WeakHashMap<Object, Boolean>());ide
若是存放在WeakHashMap中的key都存在強引用,那麼WeakHashMap就會退化爲HashMap。
使用WeakHashMap能夠忽略容量問題,提高緩存容量。只是當容量不夠時,不會OOM,內部數據會被GC回收。命中率好像沒有辦法,容我掉一片頭髮換來深度思考後給出方案。
觀察WeakHashMap源碼能夠發現,它是線程不安全的,因此在多線程場景該怎麼辦嘞?
WeakHashMap<String, String> weakHashMapintsmaze=new WeakHashMap<String, String>();
Map<String, String> intsmaze=Collections.synchronizedMap(weakHashMapintsmaze);
public class Test11 { private static final int _1MB = 1024 * 1024;// 設置大小爲1MB public static void main(String[] args) throws InterruptedException { Object value = new Object(); WeakHashMap<Object, Object> map = new WeakHashMap<Object, Object>(); for (int i = 0; i < 100; i++) { byte[] bytes = new byte[_1MB]; // bytes和value構成Entry,bytes是弱引用,沒有別人指向,就回去回收這個Entry。 map.put(bytes, value); } // 其實當咱們在循環100次添加數據時,就已經開始回收弱引用了,所以咱們會看到第一次打印的size是13,而不是100,一旦GC發生,那麼弱引用就會被清除,致使WeakHashMap的大小爲0。 // while (true) { System.gc();// 建議系統進行GC Thread.sleep(500); System.out.println(map.size());// 13 0 0 0 0 } } }
//WeakHashMap裏面EntrySet的iterator()方法返回new EntryIterator(), //EntryIterator的next和hashNext方法是對WeakHashMap的table作的遍歷。 //因此new EntrySet(),就返回WeakHashMap的table的全部元素。 public class eee { @SuppressWarnings("rawtypes") public static void main(String[] args) { Collection c = new eee().entrySet();//[6, 5, 4, 3, 2, 1] Iterator iter = c.iterator(); while (iter.hasNext()) { String entry = (String) iter.next(); System.out.println(entry); } } String[] table = new String[]{"1","2","3","4","5","6"}; String[] table1 = new String[]{"11","21","31","41","51","61"}; private transient Set<String> entrySet; public Set<String> entrySet() { Set<String> es = entrySet; return es != null ? es : (entrySet = new EntrySet());//是根據hasNext()和next()方法來肯定集合元素的。 } private class EntrySet extends AbstractSet<String> { public Iterator<String> iterator() { return new EntryIterator(); } @Override public int size() { return 0; } } private class EntryIterator<String> implements Iterator<String> { private int index; EntryIterator() { index = table.length; // index = table1.length; } public boolean hasNext() { if (index > 0) return true; else return false; } public String next() { return (String) table[--index]; // return (String) table1[--index]; } } }
當一個鍵對象被垃圾回收,那麼相應的值對象的引用會從Map中刪除。WeakHashMap可以節約存儲空間,可用來緩存那些非必須存在的數據。
get,put,size,isEmpty,containsKey,getEntry,resize,拷貝,putAll,remove,containsValue,containsNullValue,forEach都會清理髒數據。
keySet,values,entrySet不會清理髒數據。
WeakHashMap是不一樣步的。可使用 Collections.synchronizedMap 方法來構造同步的 WeakHashMap。
WeakHashMap的Key是弱引用,Value不是。WeakHashMap不會自動釋放失效的弱引用table中 Entry,僅當包含了expungeStaleEntries()的共有方法被調用的時候纔會釋放。
WeakHashMap沒有實現Clone和Serializable接口,因此不具備克隆和序列化的特性。
WeakHashMap由於gc的時候會把沒有強引用的key回收掉,因此註定了它裏面的元素不會太多,所以也就不須要像HashMap那樣元素多的時候轉化爲紅黑樹來處理了。
WeakHashmap將會移除一些死的(dread)的entry,避免持有過多死的弱引用。
ReferenceQuene可以輕易的追蹤這些死掉的弱引用。能夠講ReferenceQuene傳入WeakHashmap的構造方法(constructor)中,這樣,一旦這個弱引用裏面的對象成爲垃圾,這個弱引用將加入ReferenceQuene中。
public static void main(String args[]) { WeakHashMap<String, String> map = new WeakHashMap<String, String>(); map.put(new String("1"), "1"); map.put("2", "2"); String s = new String("3"); map.put(s, "3"); while (map.size() > 0) { try { Thread.sleep(500); } catch (InterruptedException ignored) { } System.out.println("Map Size:" + map.size()); System.out.println(map.get("1")); System.out.println(map.get("2")); System.out.println(map.get("3")); System.gc(); } } }
運行結果(一直循環當中):
Map Size:3 1 2 3
Map Size:2 null 2 3
根據String的特性,
元素「1」的key已經沒有地方引用了,因此進行了回收。
元素「2」是被放在常量池中的,因此沒有被回收。
元素「3」由於還有變量s的引用,因此也沒有進行回收。
public class ss { public static void main(String[] args) { System.out.println(test());//cde } private static String test(){ String a = new String("a"); System.out.println(a);//a WeakReference<String> b = new WeakReference<String>(a); System.out.println(b.get());//a WeakHashMap<String, Integer> weakMap = new WeakHashMap<String, Integer>(); weakMap.put(b.get(), 1);//{a=1} a = null; System.out.println("GC前b.get():"+b.get());//a System.out.println("GC前weakMap:"+weakMap);//{a=1} System.gc(); System.out.println("GC後"+b.get());//null,a=null; System.gc()後,b!=null,b中的a也被系統回收了, System.out.println("GC後"+weakMap);//{} String c = ""; try{ c = b.get().replace("a", "b");//b.get()爲null,會拋出異常。 System.out.println("C:"+c); return c; }catch(Exception e){ //finally有renturn,從finally退出。finally沒有renturn,從try退出。 //try 換成 catch 去理解就 OK 了 c = "c"; System.out.println("Exception"); return c; }finally{ c += "d"; return c + "e"; } } }
public class WeakHashMapTest { public static void main(String[] args) { WeakHashMap w= new WeakHashMap(); //三個key-value中的key 都是匿名對象,沒有強引用指向該實際對象 w.put(new String("語文"),new String("優秀")); w.put(new String("數學"), new String("及格")); w.put(new String("英語"), new String("中等")); //增長一個字符串的強引用 w.put("java", new String("特別優秀")); System.out.println(w); //{java=特別優秀, 數學=及格, 英語=中等, 語文=優秀} //通知垃圾回收機制來進行回收 System.gc(); System.runFinalization(); //再次輸出w System.out.println("第二次輸出:"+w); //第二次輸出:{java=特別優秀} } }
spliterator是java1.8引入的一種並行遍歷的機制,Iterator提供也提供了對集合數據進行遍歷的能力,但一個是順序遍歷,一個是並行遍歷。
OfInt sInt = Arrays.spliterator(arr, 2, 5);//下標,包頭不包尾。截取。
public static Spliterator.OfInt spliterator(int[] array, int startInclusive, int endExclusive) { return Spliterators.spliterator(array, startInclusive, endExclusive, Spliterator.ORDERED | Spliterator.IMMUTABLE); } public static Spliterator.OfInt spliterator(int[] array, int fromIndex, int toIndex, int additionalCharacteristics) { checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex); return new IntArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics); } public IntArraySpliterator(int[] array, int origin, int fence, int additionalCharacteristics) { this.array = array; this.index = origin; this.fence = fence; this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; } public boolean tryAdvance(IntConsumer action) {//對分割後的數組依次調用函數 if (action == null) throw new NullPointerException(); if (index >= 0 && index < fence) { action.accept(array[index++]); return true; } return false; } public OfInt trySplit() {//返回分割的數組 int lo = index, mid = (lo + fence) >>> 1; return (lo >= mid) ? null : new IntArraySpliterator(array, lo, index = mid, characteristics); } public void forEachRemaining(IntConsumer action) { int[] a; int i, hi; // 每一個元素執行給定的操做 if (action == null) throw new NullPointerException(); if ((a = array).length >= (hi = fence) && (i = index) >= 0 && i < (index = hi)) { do { action.accept(a[i]); } while (++i < hi); } } public interface IntConsumer { void accept(int value); default IntConsumer andThen(IntConsumer after) { Objects.requireNonNull(after); return (int t) -> { accept(t); after.accept(t); }; } } andThen方法是由IntConsumer 對象調用的,返回值是IntConsumer 類型:一個函數,首先調用 調用andThen方法的對象的accept()方法,然後調用after的accept方法。 public boolean tryAdvance(IntConsumer action) { if (action == null) throw new NullPointerException(); if (index >= 0 && index < fence) { action.accept(array[index++]); return true; } return false; } public class ffff { public static void main(String[] args) { int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; OfInt sInt = Arrays.spliterator(arr, 2, 5);// 返回3 4 5 IntConsumer consumer = new IntConsumer() { public void accept(int value) { System.out.println(value); } }; sInt.tryAdvance(consumer.andThen(new IntConsumer() {//先調用consumer的accept方法,在調用new IntConsumer()匿名內部類的accept方法, public void accept(int value) { System.out.println("i am after"); } })); sInt.tryAdvance(consumer.andThen(new IntConsumer() { public void accept(int value) { System.out.println("i am after"); } })); sInt.tryAdvance(consumer.andThen(new IntConsumer() { public void accept(int value) { System.out.println("i am after"); } })); sInt.tryAdvance(consumer.andThen(new IntConsumer() { public void accept(int value) { System.out.println("i am after"); } })); //3 i am after,4 i am after,5 i am after } public static void main3(String[] args) { int[] arr ={ 1, 2, 3, 4, 5, 6 }; IntConsumer consumer = new IntConsumer() {// IntConsumer的accept參數只能是int @Override public void accept(int value) { System.out.println(value); } }; OfInt sInt = Arrays.spliterator(arr);// sInt = {1,2,3,4,5,6} sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer);// 1,2,3,4,5,6 OfInt sInt1 = sInt.trySplit();// sInt1是sInt的前一半{1,2,3},sInt是後一半{4,5,6} sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer);// 只有4 5 6 sInt1.tryAdvance(consumer); sInt1.tryAdvance(consumer); sInt1.tryAdvance(consumer); sInt1.tryAdvance(consumer); sInt1.tryAdvance(consumer); sInt1.tryAdvance(consumer);// 只有1 2 3 } public static void main2(String[] args) { int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; OfInt sInt = Arrays.spliterator(arr, 2, 5);// 下標,包頭不包尾。截取。 IntConsumer consumer = new IntConsumer() { @Override public void accept(int value) { System.out.println(value); } }; sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); /* if (index >= 0 && index < fence) { consumer.accept(array[index++]); index和fence是sInt的屬性 */ sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer);// 只輸出3 4 5 ,遍歷截取後的元素。 } public static void main1(String[] args) { int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; OfInt sInt = Arrays.spliterator(arr); IntConsumer consumer = new IntConsumer() { @Override public void accept(int value) { System.out.println(value); } }; sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer); sInt.tryAdvance(consumer);// 輸出 1, 2, 3, 4, 5, 6, 7, 8, 9 } }
Spliterator就是爲了並行遍歷元素而設計的一個迭代器,jdk1.8中的集合框架中的數據結構都默認實現了spliterator,能夠和iterator順序遍歷迭代器一塊兒看。
Spliterator(splitable iterator可分割迭代器)接口是Java爲了並行遍歷數據源中的元素而設計的迭代器,這個能夠類比最先Java提供的順序遍歷迭代器Iterator,但一個是順序遍歷,一個是並行遍歷
第一個方法tryAdvance就是順序處理每一個元素,相似Iterator,若是還有元素要處理,則返回true,不然返回false
第二個方法trySplit,這就是爲Spliterator專門設計的方法,區分與普通的Iterator,該方法會把當前元素劃分一部分出去建立一個新的Spliterator做爲返回,兩個Spliterator變會並行執行,若是元素個數小到沒法劃分則返回null。二分法。
第三個方法estimateSize,該方法用於估算還剩下多少個元素須要遍歷
第四個方法characteristics,其實就是表示該Spliterator有哪些特性,用於能夠更好控制和優化Spliterator的使用,具體屬性你能夠隨便百度到,這裏就再也不贅言
從最先Java提供順序遍歷迭代器Iterator時,那個時候仍是單核時代,但如今多核時代下,順序遍歷已經不能知足需求了...如何把多個任務分配到不一樣核上並行執行,纔是能最大發揮多核的能力,因此Spliterator應運而生啦
對於Spliterator接口的設計思想,應該要提到的是Java7的Fork/Join(分支/合併)框架,總得來講就是用遞歸的方式把並行的任務拆分紅更小的子任務,而後把每一個子任務的結果合併起來生成總體結果。帶着這個理解來看看Spliterator接口提供的方法