1.map遍历
Map map = new HashMap<>();
map.put("*", "123");
map.put("+", "456");
map.put("-", "123");
System.err.println(map.toString());
//1.entrySet
Iterator<Map.Entry<String, String>> iterator3 = map.entrySet().iterator();
while(iterator3.hasNext()) {
Entry<String, String> entry = iterator3.next();
System.out.println("entrySet:"+entry.getKey()+":"+entry.getValue());
}
//2.keySet
Iterator iterator4 = map.keySet().iterator();
while(iterator4.hasNext())
System.err.println("keySet:"+map.get(iterator4.next()));
//3.values集合
Collection values = map.values();
for (Object object : values)
System.err.println("values集合:"+object);
//4.lambda表达式
map.forEach((key,value)->System.err.println("map.forEach:"+key+":"+value));
//5.stream 流遍历
map.entrySet().stream().forEach(item->{
Entry<String, String> entry = (Map.Entry<String, String>)item;
System.out.println("stream:"+entry.getKey()+":"+entry.getValue());
});
2.Set 遍历
Set set = new HashSet<>();
set.add("111");set.add("222");set.add("333");set.add("444");
//1.Iterator遍历
Iterator iterator2 = set.iterator();
while(iterator2.hasNext()) {
System.out.println("set_iterator:"+iterator2.next());
}
//2.toArray遍历
if(set.contains("444")) {
Object[] array1 = set.toArray();
for (Object object : array1) {
System.out.println("set_toArray:"+object);
}
}
//3.lambda表达式
set.forEach(key->{System.out.println("set_forEach:"+key);});
//4.stream 流遍历
set.stream().forEach(key->System.out.println("set_stream_forEach:"+key));
3.Stack 栈
线程安全的集合 Vector、 Stack 、Hashtable、 ConcurrentHashMap
/**
* 栈(Stack) 是一种 后进先出(LIFO:Last In First Out) 的数据结构
* 把元素压栈:push(E);
* 把栈顶的元素“弹出”:pop();
* 取栈顶元素但不弹出:peek()
*/
Stack stack = new Stack<>();
stack.add("123");
//把项压入堆栈顶部
stack.push("456");
stack.push("789");
System.out.println("栈元素:"+stack);
System.err.println("取栈顶元素,不移除:"+stack.peek());
System.err.println("返回对象再堆栈中的位置,以1为基数:"+stack.search("123"));
System.err.println("移除栈顶元素:"+stack.pop());
System.err.println("剩余栈元素:"+stack);
4.队列
四种队列实现方式,使用的是 ReentrantLock 锁
//队列1.ArrayBlockingQueue 是一种基于数组结构的有界阻塞队列,其构造函数需要使用int参数来指定大小,且所含的对象是以先入先出的顺序排序
//继承了 AbstractQueue 实现 BlockingQueue(继承了Queue)
ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(10);
//队列2.LinkedBlockingQueue 是一种基于链表结构的阻塞队列,其构造函数需要使用一个规定大小的参数,且所含的对象是以先入先出的顺序排序
LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue();//默认大小 0x7fffffff
//队列3.PriorityBlockingQueue 是一种具有优先级的无限阻塞队列,其所含的对象是以对象的自然排序顺序或者是构造函数进行排序。
PriorityBlockingQueue priorityBlockingQueue = new PriorityBlockingQueue();// 默认大小11
//队列4.SynchronousQueue 是一种不存储元素的阻塞队列,操作SynchronousQueue时需要等到另一个线程调用移除操作,否则操作会处于阻塞状态
SynchronousQueue synchronousQueue = new SynchronousQueue();
继承和实现
1.数组队列 ArrayBlockingQueue
(1).构造
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
public ArrayBlockingQueue(int capacity, boolean fair,
Collection<? extends E> c) {
this(capacity, fair);
final ReentrantLock lock = this.lock;
lock.lock(); // Lock only for visibility, not mutual exclusion
try {
int i = 0;
try {
for (E e : c) {
checkNotNull(e);
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}
(2).添加
public boolean add(E e) {
return super.add(e);
}
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
}
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
(3).取元素
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return itemAt(takeIndex); // null when queue is empty
} finally {
lock.unlock();
}
}
(4).简单添加和移除测试
//队列1.ArrayBlockingQueue 是一种基于数组结构的有界阻塞队列,其构造函数需要使用int参数来指定大小,且所含的对象是以先入先出的顺序排序
//继承了 AbstractQueue 实现 BlockingQueue(继承了Queue)
ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(10);
arrayBlockingQueue.add("123");//队列添加元素
arrayBlockingQueue.add("456");
try {
//put添加抛出的有异常
arrayBlockingQueue.put("789");
System.out.println("队列元素:"+arrayBlockingQueue);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("取队列顶元素,不移除:"+arrayBlockingQueue.peek()+" 此时在队列:"+arrayBlockingQueue);
System.out.println("取队列顶元素,并移除:"+arrayBlockingQueue.poll()+" 此时在队列:"+arrayBlockingQueue);
System.out.println("取队列顶元素,并移除:"+arrayBlockingQueue.remove()+" 此时在队列:"+arrayBlockingQueue);
try {
System.out.println("取队列顶元素,并移除:"+arrayBlockingQueue.take()+" 此时在队列:"+arrayBlockingQueue);
} catch (InterruptedException e) {
e.printStackTrace();
}
同样有各种遍历方式
2.链表队列 LinkedBlockingQueue
(1).构造
@Native public static final int MAX_VALUE = 0x7fffffff;
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);
}
public LinkedBlockingQueue(Collection<? extends E> c) {
this(Integer.MAX_VALUE);
final ReentrantLock putLock = this.putLock;
putLock.lock(); // Never contended, but necessary for visibility
try {
int n = 0;
for (E e : c) {
if (e == null)
throw new NullPointerException();
if (n == capacity)
throw new IllegalStateException("Queue full");
enqueue(new Node<E>(e));
++n;
}
count.set(n);
} finally {
putLock.unlock();
}
}
(2). 添加
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final AtomicInteger count = this.count;
if (count.get() == capacity)
return false;
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
if (count.get() < capacity) {
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
}
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
return c >= 0;
}
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
// Note: convention in all put/take/etc is to preset local var
// holding count negative to indicate failure unless set.
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
while (count.get() == capacity) {
notFull.await();
}
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}
(3).取元素
public E remove() {
E x = poll();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {
notEmpty.await();
}
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
public E poll() {
final AtomicInteger count = this.count;
if (count.get() == 0)
return null;
E x = null;
int c = -1;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
if (count.get() > 0) {
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
}
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
public E peek() {
if (count.get() == 0)
return null;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
Node<E> first = head.next;
if (first == null)
return null;
else
return first.item;
} finally {
takeLock.unlock();
}
}
(4).简单测试
//默认大小 0x7fffffff
LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue();
linkedBlockingQueue.add("123");
linkedBlockingQueue.offer("789");
linkedBlockingQueue.offer("101");
try {
linkedBlockingQueue.put("456");
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.err.println("此时队列:"+linkedBlockingQueue);
System.err.println("取队列顶元素,不移除:"+linkedBlockingQueue.peek()+"此时队列:"+linkedBlockingQueue);
System.err.println("取队列顶元素,并移除:"+linkedBlockingQueue.poll()+"此时队列:"+linkedBlockingQueue);
System.err.println("取队列顶元素,并移除:"+linkedBlockingQueue.remove()+"此时队列:"+linkedBlockingQueue);
try {
System.err.println("取队列顶元素,并移除:"+linkedBlockingQueue.take()+"此时队列:"+linkedBlockingQueue);
} catch (InterruptedException e) {
e.printStackTrace();
}
3.有优先级队列 priorityBlockingQueue
其所含的对象是以对象的自然排序顺序或者是构造函数进行排序,优先队列是按照堆排序原理设计的
(1).构造
private static final int DEFAULT_INITIAL_CAPACITY = 11;
public PriorityBlockingQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
public PriorityBlockingQueue(int initialCapacity) {
this(initialCapacity, null);
}
public PriorityBlockingQueue(int initialCapacity,
Comparator<? super E> comparator) {
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.lock = new ReentrantLock();
this.notEmpty = lock.newCondition();
this.comparator = comparator;
this.queue = new Object[initialCapacity];
}
public PriorityBlockingQueue(Collection<? extends E> c) {
this.lock = new ReentrantLock();
this.notEmpty = lock.newCondition();
boolean heapify = true; // true if not known to be in heap order
boolean screen = true; // true if must screen for nulls
if (c instanceof SortedSet<?>) {
SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
this.comparator = (Comparator<? super E>) ss.comparator();
heapify = false;
}
else if (c instanceof PriorityBlockingQueue<?>) {
PriorityBlockingQueue<? extends E> pq =
(PriorityBlockingQueue<? extends E>) c;
this.comparator = (Comparator<? super E>) pq.comparator();
screen = false;
if (pq.getClass() == PriorityBlockingQueue.class) // exact match
heapify = false;
}
Object[] a = c.toArray();
int n = a.length;
if (c.getClass() != java.util.ArrayList.class)
a = Arrays.copyOf(a, n, Object[].class);
if (screen && (n == 1 || this.comparator != null)) {
for (int i = 0; i < n; ++i)
if (a[i] == null)
throw new NullPointerException();
}
this.queue = a;
this.size = n;
if (heapify)
heapify();
}
(2).添加
所有往队列中加入元素的方法最后都会调用offer方法。
public boolean add(E e) {
return offer(e);
}
public void put(E e) {
offer(e); // never need to block
}
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
final ReentrantLock lock = this.lock;
lock.lock();
int n, cap;
Object[] array;
//扩容
while ((n = size) >= (cap = (array = queue).length))
tryGrow(array, cap);
try {
Comparator<? super E> cmp = comparator;
if (cmp == null)
siftUpComparable(n, e, array);
else
siftUpUsingComparator(n, e, array, cmp);
size = n + 1;
notEmpty.signal();
} finally {
lock.unlock();
}
return true;
}
方法有三个功能,分别是:扩容,插入新元素和同步 参考链接 。
(3).取元素
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return dequeue();
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
E result;
try {
while ( (result = dequeue()) == null)
notEmpty.await();
} finally {
lock.unlock();
}
return result;
}
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
E result;
try {
while ( (result = dequeue()) == null && nanos > 0)
nanos = notEmpty.awaitNanos(nanos);
} finally {
lock.unlock();
}
return result;
}
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (size == 0) ? null : (E) queue[0];
} finally {
lock.unlock();
}
}
(4).简单测试
// 默认大小11
PriorityBlockingQueue priorityBlockingQueue = new PriorityBlockingQueue();
priorityBlockingQueue.add("123");
priorityBlockingQueue.put("456");
priorityBlockingQueue.offer("789");
priorityBlockingQueue.offer("101");
System.err.println("此时队列:"+priorityBlockingQueue);
System.err.println("取队列顶元素,不移除:"+priorityBlockingQueue.peek()+"此时队列:"+priorityBlockingQueue);
System.err.println("取队列顶元素,并移除:"+priorityBlockingQueue.poll()+"此时队列:"+priorityBlockingQueue);
System.err.println("取队列顶元素,并移除:"+priorityBlockingQueue.remove()+"此时队列:"+priorityBlockingQueue);
try {
System.err.println("取队列顶元素,并移除:"+priorityBlockingQueue.take()+"此时队列:"+priorityBlockingQueue);
} catch (InterruptedException e) {
e.printStackTrace();
}
先不做过多学习
4.不存储元素队列 SynchronousQueue
SynchronousQueue 的整体设计比较抽象,在内部抽象出了两种算法实现,一种是先入先出的队列,一种是后入先出的堆栈,两种算法被两个内部类实现,而直接对外的 put,take 方法的实现就非常简单,都是直接调用两个内部类的 transfer 方法进行实现
- 队列不存储数据,所以没有大小,也无法迭代;
- 插入操作的返回必须等待另一个线程完成对应数据的删除操作,反之亦然;
- 队列由两种数据结构组成,分别是后入先出的堆栈和先入先出的队列,堆栈是非公平的,队列是公平的。
构造
默认fasle,TransferStack ,为true时 TransferQueue
public SynchronousQueue() {
this(false);
}
public SynchronousQueue(boolean fair) {
transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}
添加 add
add直接添加元素会抛出异常
SynchronousQueue synchronousQueue = new SynchronousQueue();
try {
synchronousQueue.add("123");
} catch (Exception e) {
//异常 java.lang.IllegalStateException: Queue full
e.printStackTrace();
}
System.err.println(synchronousQueue.peek()); // null
//源码
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
添加 put
try {
synchronousQueue.put("123"); //进入线程阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
源码
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
if (transferer.transfer(e, false, 0) == null) {
Thread.interrupted();
throw new InterruptedException();
}
}
更改写法,添加线程
Thread thread = new Thread() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
System.err.println("synchronousQueue:"+synchronousQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
};
thread.start();
try {
System.err.println("线程进入阻塞");
synchronousQueue.put("123");//进入线程阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
System.err.println("线程解除阻塞");
入栈和出栈
入栈指的是使用 put 等方法,把数据放到堆栈池中,出栈指的使用 take 等方法,把数据从堆栈池中拿出来,操作的对象都是堆栈头,虽然两者的一个是从堆栈头拿数据,一个是放数据,但底层实现的方法却是同一个
static final class TransferStack< E > extends Transferer< E >
TransferStack 源码transfer
@SuppressWarnings("unchecked")
E transfer(E e, boolean timed, long nanos) {
SNode s = null; // constructed/reused as needed
int mode = (e == null) ? REQUEST : DATA;
for (;;) {
SNode h = head;
if (h == null || h.mode == mode) { // empty or same-mode
if (timed && nanos <= 0) { // can't wait
if (h != null && h.isCancelled())
casHead(h, h.next); // pop cancelled node
else
return null;
} else if (casHead(h, s = snode(s, e, h, mode))) {
SNode m = awaitFulfill(s, timed, nanos);
if (m == s) { // wait was cancelled
clean(s);
return null;
}
if ((h = head) != null && h.next == s)
casHead(h, s.next); // help s's fulfiller
return (E) ((mode == REQUEST) ? m.item : s.item);
}
} else if (!isFulfilling(h.mode)) { // try to fulfill
if (h.isCancelled()) // already cancelled
casHead(h, h.next); // pop and retry
else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {
for (;;) { // loop until matched or waiters disappear
SNode m = s.next; // m is s's match
if (m == null) { // all waiters are gone
casHead(s, null); // pop fulfill node
s = null; // use new node next time
break; // restart main loop
}
SNode mn = m.next;
if (m.tryMatch(s)) {
casHead(s, mn); // pop both s and m
return (E) ((mode == REQUEST) ? m.item : s.item);
} else // lost match
s.casNext(m, mn); // help unlink
}
}
} else { // help a fulfiller
SNode m = h.next; // m is h's match
if (m == null) // waiter is gone
casHead(h, null); // pop fulfilling node
else {
SNode mn = m.next;
if (m.tryMatch(h)) // help match
casHead(h, mn); // pop both h and m
else // lost match
h.casNext(m, mn); // help unlink
}
}
}
}
- 判断是 put 方法还是 take 方法;
- 判断栈头数据是否为空,如果为空或者栈头的操作和本次操作一致,是的话走 3,否则走 5;
- 判断操作有无设置超时时间,如果设置了超时时间并且已经超时,返回 null,否则走 4;
- 如果栈头为空,把当前操作设置成栈头,或者栈头不为空,但栈头的操作和本次操作相同,也把当前操作设置成栈头,并看看其它线程能否满足自己,不能满足则阻塞自己。比如当前操作是
take,但队列中没有数据,则阻塞自己; - 如果栈头已经是阻塞住的,需要别人唤醒的,判断当前操作能否唤醒栈头,可以唤醒走 6,否则走 4;
- 把自己当作一个节点,赋值到栈头的 match 属性上,并唤醒栈头节点;
- 栈头被唤醒后,拿到 match 属性,就是把自己唤醒的节点的信息,返回。
公平的队列主要使用的是 TransferQueue 内部类的 transfer 方法
@SuppressWarnings("unchecked")
E transfer(E e, boolean timed, long nanos) {
QNode s = null; // constructed/reused as needed
boolean isData = (e != null);
for (;;) {
QNode t = tail;
QNode h = head;
if (t == null || h == null) // saw uninitialized value
continue; // spin
if (h == t || t.isData == isData) { // empty or same-mode
QNode tn = t.next;
if (t != tail) // inconsistent read
continue;
if (tn != null) { // lagging tail
advanceTail(t, tn);
continue;
}
if (timed && nanos <= 0) // can't wait
return null;
if (s == null)
s = new QNode(e, isData);
if (!t.casNext(null, s)) // failed to link in
continue;
advanceTail(t, s); // swing tail and wait
Object x = awaitFulfill(s, e, timed, nanos);
if (x == s) { // wait was cancelled
clean(t, s);
return null;
}
if (!s.isOffList()) { // not already unlinked
advanceHead(t, s); // unlink if head
if (x != null) // and forget fields
s.item = s;
s.waiter = null;
}
return (x != null) ? (E)x : e;
} else { // complementary-mode
QNode m = h.next; // node to fulfill
if (t != tail || m == null || h != head)
continue; // inconsistent read
Object x = m.item;
if (isData == (x != null) || // m already fulfilled
x == m || // m cancelled
!m.casItem(x, e)) { // lost CAS
advanceHead(h, m); // dequeue and retry
continue;
}
advanceHead(h, m); // successfully fulfilled
LockSupport.unpark(m.waiter);
return (x != null) ? (E)x : e;
}
}
}
源码比较复杂,我们需要搞清楚的是,线程被阻塞住后,当前线程是如何把自己的数据传给阻塞线程的。为了方便说明,我们假设线程 1 往队列中 take 数据 ,被阻塞住了,变成阻塞线程 A ,然后线程 2 开始往队列中 put 数据 B,大致的流程是这样的:
- 线程 1 从队列中拿数据,发现队列中没有数据,于是被阻塞,成为 A ;
- 线程 2 往队尾 put 数据,会从队尾往前找到第一个被阻塞的节点,假设此时能找到的就是节点 A,然后线程 B 把将 put的数据放到节点 A 的 item 属性里面,并唤醒线程 1;
- 线程 1 被唤醒后,就能从 A.item 里面拿到线程 2 put 的数据了,线程 1 成功返回。
从这个过程中,我们能看出公平主要体现在,每次 put 数据的时候,都 put 到队尾上,而每次拿数据时,并不是直接从堆头拿数据,而是从队尾往前寻找第一个被阻塞的线程,这样就会按照顺序释放被阻塞的线程