整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

List<T>的初始大小

List<T>的初始大小

起来真是丢人,干了这么多年.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老师发布的基础视频,明天做的案例按照老师讲解的案例去做。