package io.netty.util;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
/**
* Default {@link AttributeMap} implementation which use simple synchronization per bucket to keep the memory overhead
* as low as possible.
*/
public class DefaultAttributeMap implements AttributeMap {
//以原子方式更新attributes变量的引用
@SuppressWarnings("rawtypes")
private static final AtomicReferenceFieldUpdater<DefaultAttributeMap, AtomicReferenceArray> updater =
AtomicReferenceFieldUpdater.newUpdater(DefaultAttributeMap.class, AtomicReferenceArray.class, "attributes");
//默认桶的大小
private static final int BUCKET_SIZE = 4;
//掩码 桶大小-1
private static final int MASK = BUCKET_SIZE - 1;
//延迟初始化,节约内存
// Initialize lazily to reduce memory consumption; updated by AtomicReferenceFieldUpdater above.
@SuppressWarnings("UnusedDeclaration")
private volatile AtomicReferenceArray<DefaultAttribute<?>> attributes;
@SuppressWarnings("unchecked")
@Override
public <T> Attribute<T> attr(AttributeKey<T> key) {
if (key == null) {
throw new NullPointerException("key");
}
AtomicReferenceArray<DefaultAttribute<?>> attributes = this.attributes;
//当attributes为空时则创建它,默认数组长度4
if (attributes == null) {
//没有使用ConcurrentHashMap为了节约内存
// Not using ConcurrentHashMap due to high memory consumption.
attributes = new AtomicReferenceArray<DefaultAttribute<?>>(BUCKET_SIZE);
//原子方式更新attributes,如果attributes为null则把新创建的对象赋值
//原子方式更新解决了并发赋值问题
if (!updater.compareAndSet(this, null, attributes)) {
attributes = this.attributes;
}
}
//根据key计算下标
int i = index(key);
//返回attributes数组中的第一个元素
DefaultAttribute<?> head = attributes.get(i);
//头部为空说明第一次添加,这个方法可能多个线程同时调用,因为判断head全部为null
if (head == null) {
// No head exists yet which means we may be able to add the attribute without synchronization and just
// use compare and set. At worst we need to fallback to synchronization and waste two allocations.
//创建一个空对象为链表结构的起点
head = new DefaultAttribute();
//创建一个attr对象,把head传进去
DefaultAttribute<T> attr = new DefaultAttribute<T>(head, key);
//链表头head的next = attr
head.next = attr;
//attr的prev = head
attr.prev = head;
//给数组i位置赋值,这里用compareAndSet原子更新方法解决并发问题
//只有i位置为null能够设置成功,且只有一个线程能设置成功
if (attributes.compareAndSet(i, null, head)) {
//设置成功后返回attr
// we were able to add it so return the attr right away
return attr;
} else {
//设置失败的,说明数组i位置已经被其它线程赋值
//所以要把head重新赋值,不能用上面new出来的head,需要拿到之前线程设置进去的head
head = attributes.get(i);
}
}
//对head同步加锁
synchronized (head) {
//curr 赋值为head head为链表结构的第一个变量
DefaultAttribute<?> curr = head;
for (;;) {
//依次获取next
DefaultAttribute<?> next = curr.next;
//next==null,说明curr为最后一个元素
if (next == null) {
//创建一个新对象传入head和key
DefaultAttribute<T> attr = new DefaultAttribute<T>(head, key);
//curr后面指向attr
curr.next = attr;
//attr的前面指向curr
attr.prev = curr;
//返回新对象
return attr;
}
//如果next的key等于传入的key,并且没有被移除
if (next.key == key && !next.removed) {
//这直接返回next
return (Attribute<T>) next;
}
//否则把curr变量指向下一个元素
curr = next;
}
}
}
@Override
public <T> boolean hasAttr(AttributeKey<T> key) {
if (key == null) {
throw new NullPointerException("key");
}
//attributes为null直接返回false
AtomicReferenceArray<DefaultAttribute<?>> attributes = this.attributes;
if (attributes == null) {
// no attribute exists
return false;
}
//计算数组下标
int i = index(key);
//获取头 为空直接返回false
DefaultAttribute<?> head = attributes.get(i);
if (head == null) {
// No attribute exists which point to the bucket in which the head should be located
return false;
}
//对head同步加锁
// We need to synchronize on the head.
synchronized (head) {
// Start with head.next as the head itself does not store an attribute.
//从head的下一个开始,因为head不存储元素
DefaultAttribute<?> curr = head.next;
//为null说明没有节点了
while (curr != null) {
//key一致并且没有被移除则返回true
if (curr.key == key && !curr.removed) {
return true;
}
//curr指向下一个
curr = curr.next;
}
return false;
}
}
private static int index(AttributeKey<?> key) {
//与掩码&运算,数值肯定<=mask 正好是数组下标
return key.id() & MASK;
}
}
Netty源码分析-DefaultAttributeMap
原创
©著作权归作者所有:来自51CTO博客作者大新哥666的原创作品,请联系作者获取转载授权,否则将追究法律责任
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
Netty源码分析
netty源码分析netty模型selector模式对普通NIO的性能提升NIO可以同时使用多个selector是...
netty 模型 客户端 数据 性能提升 -
CDH yarn 内存限制
环境及软件说明 环境说明 本人PC虚拟机VM10,里面安装了3台CentOS7.4 .集群环境规划如下: CPU IP &n
CDH yarn 内存限制 mysql cloudera oracle