弱引用(WeakReference)的特性是:当gc线程发现某个对象只有弱引用指向它,那么就会将其销毁并回收内存。WeakReference也会被加入到引用队列queue中。

它的特殊之处在于 WeakHashMap 里的entry可能会被GC自动删除,即使程序员没有调用remove()或者clear()方法。

可能发生如下情况:

  • 调用两次size()方法返回不同的值;
  • 两次调用isEmpty()方法,第一次返回false,第二次返回true
  • 两次调用containsKey()方法,第一次返回true,第二次返回false,尽管两次使用的是同一个key
  • 两次调用get()方法,第一次返回一个value,第二次返回null,尽管两次使用的是同一个对象。

WeekHashMap 的这个特点特别适用于需要缓存的场景。

GC判断某个对象是否可被回收的依据是,是否有有效的引用指向该对象。

这里的“有效引用”并不包括弱引用。也就是说,虽然弱引用可以用来访问对象。

将一对key, value放入到 WeakHashMap 里并不能避免该key对应的内存区域被GC回收。

既然有 WeekHashMap,是否有 WeekHashSet 呢?答案是没有,不过Java Collections工具类给出了解决方案,

// 将WeakHashMap包装成一个Set

Set<Object> weakHashSet = Collections.newSetFromMap(new WeakHashMap<Object, Boolean>());

如果存放在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(); //return null 那么new EntrySet()就没有元素了。
}
@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,拷贝,putAllremovecontainsValuecontainsNullValueforEach都会清理脏数据。

keySetvaluesentrySet不会清理脏数据。

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接口提供的方法

WeakhashMap源码1的更多相关文章

  1. Java WeakHashMap 源码解析

    前面把基于特定数据结构的Map介绍完了,它们分别利用了相应数据结构的特点来实现特殊的目的,像HashMap利用哈希表的快速插入.查找实现O(1)的增删改查,TreeMap则利用了红黑树来保证key的有 ...

  2. 死磕 java集合之WeakHashMap源码分析

    欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. 简介 WeakHashMap是一种弱引用map,内部的key会存储为弱引用,当jvm gc的时 ...

  3. WeakHashMap源码解读

    1. 简介 本文基于JDK8u111的源码分析WeakHashMap的一些主要方法的实现. 2. 数据结构 就数据结构来说WeakHashMap与HashMap原理差不多,都是拉链法来解决哈希冲突. ...

  4. WeakHashMap源码分析

    WeakHashMap是一种弱引用map,内部的key会存储为弱引用, 当jvm gc的时候,如果这些key没有强引用存在的话,会被gc回收掉, 下一次当我们操作map的时候会把对应的Entry整个删 ...

  5. WeakhashMap源码2

    public class WeakHashMapIteratorTest { @SuppressWarnings({ "rawtypes", "unchecked&quo ...

  6. WeakHashMap 源码分析

    WeakHashMap WeakHashMap 能解决什么问题?什么时候使用 WeakHashMap? 1)WeakHashMap 是基于弱引用键实现 Map 接口的哈希表.当内存紧张,并且键只被 W ...

  7. Java 集合系列13之 WeakHashMap详细介绍(源码解析)和使用示例

    概要 这一章,我们对WeakHashMap进行学习.我们先对WeakHashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用WeakHashMap.第1部分 WeakHashMap介绍 ...

  8. JDK源码分析(9)之 WeakHashMap 相关

    平时我们使用最多的数据结构肯定是 HashMap,但是在使用的时候我们必须知道每个键值对的生命周期,并且手动清除它:但是如果我们不是很清楚它的生命周期,这时候就比较麻烦:通常有这样几种处理方式: 由一 ...

  9. WeakHashMap,源码解读

    概述 WeakHashMap也是Map接口的一个实现类,它与HashMap相似,也是一个哈希表,存储key-value pair,而且也是非线程安全的.不过WeakHashMap并没有引入红黑树来尽量 ...

随机推荐

  1. 我是如何一步步编码完成万仓网ERP系统的(十)产品库设计 6.属性项和类别关联

    https://www.cnblogs.com/smh188/p/11533668.html(我是如何一步步编码完成万仓网ERP系统的(一)系统架构) https://www.cnblogs.com/ ...

  2. Delphi - Logs记录,函数实现MsgDsp

    Logs记录-函数实现MsgDsp 大多数时候,我们不太希望消息以交互的形式出现,这个时候我们可以在窗体上放置一个Memo,然后单独开一个线程进行监视,从而实现把消息实时的显示出来,便于开发者分析. ...

  3. 并发编程需要场景化:CountDownLatch

  4. ASP.NET MVC IOC 之 Autofac(三)-webform中应用

    在webform中应用autofac,只有global中的写法不一样,其他使用方式都一样 nuget上引用: global中的写法: private void AutoFacRegister() { ...

  5. ASP.NET Core MVC上传文件

    使用模型绑定上传小文件 HTML代码: <form method="post" enctype="multipart/form-data" asp-con ...

  6. json方式的面向对象、拖拽

    //json方式的面向对象 var obj= { a:, b:, c:function(){ alert( } } obj.c();//12 //命名空间 var miaov={}; miaov.co ...

  7. scrapy设置logger日志

    1.在settings中设置log级别,在settings.py中添加一行: LOG_LEVEL = 'WARNING' Scrapy提供5层logging级别: CRITICAL - 严重错误 ER ...

  8. windows 给mysql安装innodb引擎

    1.启用InnoDB    打开my.ini文件,找到[skip-innodb],在前面加# 2.更改数据库默认引擎为InnoDB    打开my.ini文件,更改[default-storage-e ...

  9. Chrome无界面启动使用

    Method1: from selenium import webdriver # 创建chrome参数对象opt = webdriver.ChromeOptions() # 把chrome设置成无界 ...

  10. Django模板技术

    Django模板技术 作者:尹正杰  版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.模板概述 1>.模板的作用 如果使用react实现前端页面,其实Django就没有必须使用模板,它其 ...