JDK源码学习笔记1-AbstractMap

AbstractMap这个主要是为了减轻实现Map接口的任务而设计的,这样一些简单通用的方法就不用各种Map自己一一实现了。

在看这个类的时候,我发现了2个地方是我需要学习的:

1、根据需要,一个方法可以写成只抛出一个异常

public V put(K key, V value) {    
    throw new UnsupportedOperationException();
}

AbstractMap实现了Map接口,因此必须要有put()方法,而像我的话可能方法中直接就什么都不写了。但显然源码中技高一筹,就只抛出个异常, 这样继承AbstractMap的子类如果没有自己实现put()方法就会抛出这个异常,告诉编码者需要自己去实现这个方法,而不是什么反应都没有了。虽然是很小的细节,但对以后可能出现的问题做了预防,很值得学习。

2、transient和volatile关键词的使用

transient volatile Set<K> keySet = null;
transient volatile Collection<V> values = null;

下面给出网络上找到的对这两个关键词的解释:

transient是变量修饰符,表明该字段不是对象持久状态的一部分,储存的时候不用储存,比如序列化这个对象时,该字段是不会储存的。

volatile也是变量修饰符,只能用来修饰变量。volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。 而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

在此解释一下Java的内存机制:

Java使用一个主内存来保存变量当前值,而每个线程则有其独立的工作内存。线程访问变量的时候会将变量的值拷贝到自己的工作内存中,这样,当线程对自己工作内存中的变量进行操作之后,就造成了工作内存中的变量拷贝的值与主内存中的变量值不同。

Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。

这样当多个线程同时某个对象交互时,就必须要注意到要让线程及时地得到共享成员变量的变化。

而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。

使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。

由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。

这里的keySet和values主要是用来缓存keySet()和values()方法的返回值,因此不用持久。keySet()和values()方法都没有用synchronized修饰,但他们的返回值是很容易会变的,用volatile就能在很大程度上解决多线程带来的数据不一致问题,但还是有很小的可能性会出现数据不一致。我的理解是,用volatile比用synchronized效率高,但没那么保险,这里是一个折中方案。不知道对不对,希望对这个问题认识比较深刻的大牛能够指正。

你可能感兴趣的:(JDK源码学习笔记1-AbstractMap)