起来真是丢人,干了这么多年.net ,才知道List<T> 初始大小是4,还是调试一段代码发现的。
情况是这样的,给List<T> Add 一个T,结果发现items 里的长度变成了4 ,找了半天原因没发现代码有什么问题。就上网查,才发现有这么回事,如果超过了4,长度就会变成8,如下图
知道的别嘲笑我啊。
言
CopyOnWriteArrayList是一个线程安全集合,原理简单说就是:在保证线程安全的前提下,牺牲掉写操作的效率来保证读操作的高效。所谓CopyOnWrite就是通过复制的方式来完成对数据的修改,在进行修改的时候,复制一个新数组,在新数组上面进行修改操作,这样就保证了不改变老数组,也就没有一写多读数据不一致的问题了。
具体的实现来看源码,JDK 8。
CopyOnWriteArrayList
定义
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
在定义上和ArrayList大差不差,不过多解释,有兴趣可以看之前关于ArrayList的文章。
属性
一个是Lock,另一个是一个对象数组。
/** The lock protecting all mutators *///一把锁transient final ReentrantLock lock=new ReentrantLock();
/** The array, accessed only via getArray/setArray. *///一个对象数组,只从方法getArray/setArray处接受值//volatile后面会有专门的文章来说明private volatile transient Object[] array;
初始化
CopyOnWriteArrayList的初始化容量是0,分为这样的几个步骤。
//在无参构造方法中会调用setArray方法,参数是一个空的对象数组,然后通过setArray把这个空的数组赋值给属性arraypublic CopyOnWriteArrayList() {
setArray(new Object[0]);
}final void setArray(Object[] a) {
array=a;
}
需要说明的是另一个有参构造方法,参数可以是一个集合
//按照集合的迭代器返回的顺序创建一个包含指定集合元素的列表public CopyOnWriteArrayList(Collection<? extends E> c) {
//将集合转为数组
Object[] elements=c.toArray();//elements不能够是一个空的对象数组 为什么要if这样一个条件嘞 因为属性中需要赋值的是一个对象数组 所以如果if成立执行的就是把原数组变为一个对象数组 如果本身就是对象数组也就不用转了
if (elements.getClass() !=Object[].class)
elements=Arrays.copyOf(elements, elements.length, Object[].class);
//赋值给属性
setArray(elements);
}
方法
add(E e)
添加一个新元素到list的尾部。
public boolean add(E e) {
//锁 1.5新版本的锁 已经不用synchronized了
final ReentrantLock lock=this.lock;
//加锁
lock.lock();
try {
//getArray获取属性值 就是老数组
Object[] elements=getArray();
int len=elements.length;
//这里是重点 在这里 复制老数组得到了一个长度+1的新数组
Object[] newElements=Arrays.copyOf(elements, len + 1);
//添加元素
newElements[len]=e;
//用新数组取代老数组
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
从add方法中我们可以看到所谓的CopyOnWrite是如何实现的,在需要修改的时候,复制一个新数组,在新数组上修改,修改结束取代老数组,这样保证了修改操作不影响老数组的正常读取,另修改操作是加锁的,也就是说没有了线程不安全的问题。
和ArrayList相比较,效率比较低,只添加一个元素的情况下(初始容量均为0),用时是ArrayList的5倍左右,但是随着CopyOnWriteArrayList中元素的增加,CopyOnWriteArrayList的修改代价将越来越昂贵。
除了添加其他的修改操作也都是这样的套路,不做过多解释,如remove,也是加锁,复制新数组。
public E remove(int index) {
final ReentrantLock lock=this.lock;
lock.lock();
try {
Object[] elements=getArray();
int len=elements.length;
E oldValue=get(elements, index);
int numMoved=len - index - 1;
if (numMoved==0)
setArray(Arrays.copyOf(elements, len - 1));
else {
// 复制一个新数组
Object[] newElements=new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index + 1, newElements, index,
numMoved);
setArray(newElements);
}
return oldValue;
} finally {
lock.unlock();
}
}
#####get
public E get(int index) {
return get(getArray(), index);
}//按照下标获取数组中对应的元素private E get(Object[] a, int index) {
return (E) a[index];
}
读取的方法就很简单了,按照下标获取对应的元素。
CopyOnWriteArrayList总结
1. 读写分离,我们修改的是新数组,读取的是老数组,不是一个对象,实现了读写分离。这种技术数据库用的非常多,在高并发下为了缓解数据库的压力,即使做了缓存也要对数据库做读写分离,读的时候使用读库,写的时候使用写库,然后读库、写库之间进行一定的同步,这样就避免同一个库上读、写的IO操作太多。
2. 场景:读操作远多于修改操作
架构师视频资料分享链接:
data:text/html;charset=UTF-8;base64,
5p625p6E5biI5a2m5Lmg5Lqk5rWB576k5Y+35pivNTc1NzUxODU0Cg==
复制粘贴在网站即可!
在html中列表分为无序列表、有序列表和自定义列表(项目列表)。接下来就看看他们有什么不同吧!
作用:如果说table标签是用来显示数据的,那么列表标签就是用来进行html页面布局的。
语法:
<ul>
<li></li>
</ul>
<ul></ul>标签中只能且必须嵌套<li></li>标签。li标签之间没有先后顺序,是并列存在的。li标签里可以容纳文本、数据、图片、超链接等内容。跟table一样,列表标签也自带样式属性,但为了代码统一,我们还是会使用css来设置。
代码示例:
<h2>无序列表:</h2>
<ul>
<li>苹果</li>
<li>橘子</li>
<li>香蕉</li>
</ul>
运行界面:
语法:
<ol>
<li></li>
</ol>
<ol></ol>标签里面只能嵌套<li></li>标签,在这里li标签是有顺序的。
代码示例:
<h2>有序列表:</h2>
<ol>
<li>苹果</li>
<li>橘子</li>
<li>香蕉</li>
</ol>
运行界面:
语法:
<dl>
<dt></dt>
<dd></dd>
</dl>
<dl></dl>标签:定义列表
<dt></dt>标签:列表标题
<dd></dd>标签:列表内容
一个dd标签是对dt标签标题的说明。这两个标签中可以包含任何标签。
代码示例:
<h2>自定义列表:</h2>
<!-- dl:外层标签 dt:项目标题 dd:项目内容 -->
<dl>
<dt>水果种类</dt>
<dd>苹果</dd>
<dd>橘子</dd>
<dd>香蕉</dd>
</dl>
运行界面:
作用:收集用户信息。一般用在注册界面等。
组成:一个完整的表单中包含表单域(整个填写界面所有信息)、表单控件(表单元素)和提示信息(表单控件的提示作用)3个部分。
表单域:是一个包含表单元素的区域。
<form>标签用于定义表单域,实现用户信息的收集和传递。
作用:将其区域范围内的信息收集并传送给服务器。
语法:
<form action=”url地址” method=”提交方式” name=”表单域名称”>
各种表单控件
</form>
注:action:url地址,指定接收并处理表单数据的服务器程序的url地址。
method:用于设置表单数据的提交方式。
method=”get”:提交数据时,地址栏可查看到数据。数据量少且安全级别不高时使用。
method=”post”:提交数据时,地址栏数据是加密的。
name:表单域的名称。用于区分同一页面下的不同表单域。
1.input输入表单元素:
语法:<input type=””>,依据type属性值不同区分不同控件。
文本框:<input type=”text”>。单行输入字段,默认宽度20个字符。输入的文字可见。
密码框:<input type=”password”>。输入内容默认不可见。
单选框:<input type=”radio”>,默认情况下选中后无法取消。
注:为实现多选一状态,需要将所有的单选框控件具有同一个name名。
复选框:<input type=”checkbox”>,选中后可以更改可以取消。
提交按钮:<input type=”submit”>,默认按钮中的提示文字是提交,可以通过value值进行更改内容。点击提交按钮后会把表单数据发送到服务器。
重置按钮:<input type=”reset”>,默认按钮中的提示文字是重置,可以通过value值进行更改内容。点击后会清楚表单中的所有数据。
普通按钮:<input type=”button”>
文件域:<input type=”file”>,用来选择文件,一般适用于文件上传。
label标签:标注标签,配合input控件一起使用
作用:绑定表单控件,扩大点击范围。
当点击label标签的内容时,系统会自动选中该表单控件。
代码示例:
<h1>label标签</h1>
<form>
<label for="text">用户名:</label>
<input type="text" name="用户名" id="text"><br>
<label for="password">密码:</label>
<input type="password" id="password"><br>
<label for="男">男</label>
<input type="radio" name="sex" id="男">
<label for="女">女</label>
<input type="radio" name="sex" id="女"><br>
</form>
运行界面:
Input控件属性:
name:用户自定义,提示input元素的名称。给后台工作人员的提示。
value:用户自定义,提示input元素的内容值。给后台的提示。在文本框控件中会显示该内容,单选框和复选框则显示不出来。
checked:默认选中状态。主要用于单选按钮和复选按钮中。
maxlength:正整数,规定输入字段中的字符最大长度。
input代码示例:
<h2>表单标签</h2>
<form>
用户名:<input type="text" maxlength="15" value="请输入用户名"><br>
密 码:<input type="password"><br>
性 别:<input type="radio" name="sex" value="男">男
<input type="radio" name="sex" value="女">女<br>
爱 好:<input type="checkbox" name="like" value="swim">游泳
<input type="checkbox" name="like" value="健身">健身
<input type="checkbox" name="like" value="run">跑步<br>
<input type="submit">
<input type="reset"><br>
<input type="submit" value="注册">
<input type="reset" value="清空"><br>
<!-- 后期结合js搭配使用 -->
<!-- 按钮选框在默认情况下是没有文字内容的,需要添加value值设置文字内容 -->
<input type="button" value="获取短信验证码"><br>
上传头像:<input type="file">
</form>
运行界面:
2.select下拉表单元素:
使用场景:地址选择、职业分类、学校分类等。
select标签:定义下拉列表。
语法:
<select>
<option></option>
</select>
代码示例:
<h1>下拉表单</h1>
<form>
<label for="adress">籍贯:</label>
<select name="" id="">
<option value="">北京</option>
<option value="">河北</option>
<option value="">上海</option>
<option value="">广州</option>
<option value="">深圳</option>
</select>
</form>
运行界面:
3.textrea文本域表单控件
使用场景:留言、介绍、评论等。
语法:
<textrea rows=”” cols=””>文本内容</textrea>
跟文本框控件不同,它是多行文本输入框,可以自行设定行数以及一行容纳多少字数。
rows=“每行可输入的字符数”,
cols=“显示的行数”。
这两个样式属性实际开发中大多使用css就可以改变操作。
代码示例:
<h1>文本域表单元素</h1>
<form action="">
<label for="textrea">今日反馈:</label><br>
<textarea name="" id="" cols="15" rows="10">今日反馈</textarea>
</form>
运行界面:
关于HTML基础内容就学习到这里了,明天练习一个综合案例。对了,现在跟学的是黑马前端的pink老师发布的基础视频,明天做的案例按照老师讲解的案例去做。
*请认真填写需求信息,我们会在24小时内与您取得联系。