同步操作将从 Java精选/Ebooks 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
实例代码如下:
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class SortList {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 10,5, 4, 2, 9, 7, 3, 8, 6);
System.out.print("原始数据:");
list.forEach(n -> {
System.out.print(n + ", ");
});
System.out.print("\n\r升序排列:");
Collections.sort(list);
list.forEach(n -> {
System.out.print(n + ", ");
});
System.out.print("\n\r降序排列:");
Collections.reverse(list);
list.forEach(n -> {
System.out.print(n + ", ");
});
}
}
执行结果如下:
原始数据:1, 10, 5, 4, 2, 9, 7, 3, 8, 6,
升序排列:1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
降序排列:10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
HashMap多线程会导致死循环的主要原因在于并发下的Rehash()方法会造成元素之间会形成一个循环链表。
注意的是JDK1.8及以上解决了这个问题,但是不建议在多线程下使用HashMap,因为多线程下使用HashMap还是会存在其他问题比如数据丢失。在并发环境下推荐使用ConcurrentHashMap,后续篇幅中会写相关的文章。
当类中要操作的引用数据类型不确定时,在JDK1.5版本前使用Object来完成扩展,JDK1.5后推荐使用泛型来完成扩展,同时保证安全性。
public class LinkList {
public Node head;
public Node current;
//方法:向链表中添加数据
public void add(int data) {
// 判断链表为空
if (head == null) {// 如果头结点为空,说明这个链表还没有创建,那就把新的结点赋给头结点
head = new Node(data);
current = head;
} else {
// 创建新的结点,放在当前节点的后面(把新的结点合链表进行关联)
current.next = new Node(data);
// 把链表的当前索引向后移动一位
current = current.next; // 此步操作完成之后,current结点指向新添加的那个结点
}
}
//方法:遍历链表(打印输出链表。方法的参数表示从节点node开始进行遍历
public void print(Node node) {
if (node == null) {
return;
}
current = node;
while (current != null) {
System.out.println(current.data);
current = current.next;
}
}
class Node {
//注:此处的两个成员变量权限不能为private,因为private的权限是仅对本类访问。
int data; // 数据域
Node next;// 指针域
public Node(int data) {
this.data = data;
}
}
public static void main(String[] args) {
LinkList list = new LinkList();
//向LinkList中添加数据
for (int i = 0; i < 10; i++) {
list.add(i);
}
list.print(list.head);// 从head节点开始遍历输出
}
}
执行结果
0
1
2
3
4
5
6
7
8
9
查看上述代码,Node节点采用的是内部类来表示。使用内部类的最大好处是可以和外部类进行私有操作的互相访问。
内部类访问的特点是:内部类可以直接访问外部类的成员,包括私有;外部类要访问内部类的成员,必须先创建对象。
为了方便添加和遍历的操作,在LinkList类中添加一个成员变量current,用来表示当前节点的索引。
遍历链表的方法中,参数node表示从node节点开始遍历,不一定要从head节点遍历。
集合类接口指定了一组叫做元素的对象。集合类接口的每一种具体的实现类都可以选择以它自己的方式对元素进行保存和排序。有的集合类允许重复的键,有些不允许。
Java集合类提供了一套设计良好的支持对一组对象进行操作的接口和类。Java集合类里面最基本的接口有:
Collection:代表一组对象,每一个对象都是它的子元素。
Set:不包含重复元素的Collection。
List:有顺序的collection,并且可以包含重复元素。
Map:可以把键(key)映射到值(value)的对象,键不能重复。
Iterator是JDK 1.2版本中添加的接口,支持HashMap、ArrayList等集合遍历接口。Iterator是支持fail-fast机制,当多个线程对同一个集合的内容进行操作时可能产生fail-fast事件。
Iterator有3个方法接口,Iterator能读取集合数据且可以对数据进行删除操作,而Enumeration只有2个方法接口,通过Enumeration只能读取集合的数据,而不能对数据进行修改。
Enumeration接口的处理性能是Iterator的两倍且内存使用也更少,但是Iterator接口比Enumeration要安全很多,主要是因为其他线程不能够修改正在被iterator遍历的集合中的对象。同时,Iterator允许调用者删除底层集合里面的元素,这对Enumeration接口来说是不可能的。
迭代器取代了Java集合框架中的Enumeration。迭代器允许调用者从集合中移除元素,而Enumeration不能实现。
Enumeration是JDK 1.0版本中添加的接口。Enumeration的方法接口为Vector、Hashtable等类提供了遍历接口。Enumeration本身不支持同步,而在Vector、Hashtable实现Enumeration时添加了同步。
HashCode相同,通过equals比较内容获取值对象。
并发List
Vector和CopyOnWriteArrayList是两个线程安全的List,Vector读写操作都用了同步,相对来说更适用于写多读少的场合,CopyOnWriteArrayList在写的时候会复制一个副本,对副本写,写完用副本替换原值,读的时候不需要同步,适用于写少读多的场合。
并发Set
CopyOnWriteArraySet基于CopyOnWriteArrayList来实现的,只是在不允许存在重复的对象这个特性上遍历处理了一下。
并发Map
ConcurrentHashMap是专用于高并发的Map实现,内部实现进行了锁分离,get操作是无锁的。
并发Queue
在并发队列上JDK提供了两套实现,一个是以ConcurrentLinkedQueue为代表的高性能队列,一个是以BlockingQueue接口为代表的阻塞队列。ConcurrentLinkedQueue适用于高并发场景下的队列,通过无锁的方式实现,通常ConcurrentLinkedQueue的性能要优于BlockingQueue。BlockingQueue的典型应用场景是生产者-消费者模式中,如果生产快于消费,生产队列装满时会阻塞,等待消费。
并发Dueue
Queue是一种双端队列,它允许在队列的头部和尾部进行出队和入队的操作。Dueue实现类有非线程安全的LinkedList、ArrayDueue和线程安全的LinkedBlockingDueue。LinkedBlockingDueue没有进行读写锁的分离,因此同一时间只能有一个线程对其操作,因此在高并发应用中,它的性能要远远低于LinkedBlockingQueue,更低于ConcurrentLinkedQueue。
并发锁重入锁ReentrantLock
ReentrantLock是一种互斥锁的实现,就是一次最多只能一个线程拿到锁;
读写锁ReadWriteLock
读写锁有读取和写入两种锁,读取锁允许多个读取的线程同时持有,而写入锁只能有一个线程持有。
条件Condition
调用Condition对象的相关方法,可以方便的挂起和唤醒线程。
HashMap实现了Map接口,Map接口对键值对进行映射。
Map中不允许重复的键。Map接口有两个基本的实现,HashMap和TreeMap。TreeMap保存了对象的排列次序,而HashMap则不能。HashMap允许键和值为null。
HashMap是非synchronized的,但collection框架提供方法能保证HashMap synchronized,这样多个线程同时访问HashMap时,能保证只有一个线程更改Map。
public Object put(Object Key,Object value);
该方法用来将元素添加到map中。
1、计算关于key的hashcode值(与Key.hashCode的高16位做异或运算)
2、如果散列表为空时,调用resize()初始化散列表
3、如果没有发生碰撞,直接添加元素到散列表中去
4、如果发生了碰撞(hashCode值相同),进行三种判断
1)若key地址相同或者equals后内容相同,则替换旧值
2)如果是红黑树结构,就调用树的插入方法
3)链表结构,循环遍历直到链表中某个节点为空,尾插法进行插入,插入之后判断链表个数是否到达变成红黑树的阙值8;也可以遍历到有节点与插入元素的哈希值和内容相同,进行覆盖。
5、如果桶满了大于阀值,则resize进行扩容
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。