public interface Iterator<E> {
default void remove() {
throw new UnsupportedOperationException("remove");
}
}
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
}
private class Itr implements Iterator<E> {
int lastRet = -1;//默认为-1
//执行第一步
public void remove() {
if (lastRet < 0)
//报错1
throw new IllegalStateException();
//使用next后,进入这里
checkForComodification();
}
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
}
所以list会报 IllegalStateException
List<Integer> list = Arrays.asList(1, 2, 3);
Iterator<Integer> iterator = list.iterator();
//直接移除报错:Exception in thread "Thread-0" java.lang.IllegalStateException
iterator.remove();
//依然是同样的错
List<Integer> list = new ArrayList<>();
List<Integer> list = new ArrayList<>();
list.add(1);
Iterator<Integer> iterator = list.iterator();
iterator.next();
iterator.remove();
List<Integer> list = Arrays.asList(1, 2, 3);//固定长度的ArrayList
System.out.println(iterator.next());
//Exception in thread "Thread-0" java.lang.UnsupportedOperationException
iterator.remove();
List<Integer> list = Arrays.asList(1, 2, 3);
list.add(333);
//Exception in thread "main" java.lang.UnsupportedOperationException
//最终调用的源码如下。因为:Arrays的内部类ArrayList,没添加的方法。
//会调用父类的 AbstractList,是 扔异常的
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
Arrays.asList(1,2,3) //是一个特殊的 ArrayList
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
//核心是 Arrays的内部类
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable{
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
}
public void remove() {
if (lastRet < 0)
//报错1
throw new IllegalStateException();
//使用next后,进入这里。lastRet 为 0
checkForComodification();
try {
//将会执行 remove的错误。即:最顶层的错误
AbstractList.this.remove(lastRet);
}
}
//这里并没有 并发异常,不走这个错误
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
List<Integer> list = new ArrayList();
list.add(1);
Iterator<Integer> iterator = list.iterator();
//原来只有一个元素。hashNext第二次会返回 false
//现在 hashNext 第二次依然返回true
while (iterator.hasNext()) {
//第二次 进入 next 方法。进入检查的方法,就会报错:
//Exception in thread "main" java.util.ConcurrentModificationException
iterator.next();
//因为 这里加入了一个元素。
list.add(4);
}
public E next() {
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
//底层是 cas,会复制一份
// private transient volatile Object[] array;
List<Integer> list = new CopyOnWriteArrayList<>();
list.add(1);
Iterator<Integer> iterator = list.iterator();
//第二次循环,hasNext 会返回 false
while (iterator.hasNext()) {
iterator.next();
list.add(4);
}
迭代器:Java Collection 定义了两种类型的迭代器:fail-fast和fail-safe。
fail-fast:如果集合在迭代时被修改,则立即抛出 ConcurrentModificationException 。
protected transient int modCount = 0;
int expectedModCount = modCount;
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
fail-safe:如果集合在迭代时被修改,不会抛出 ConcurrentModificationException,
并发修改:简单的说,并发修改在一个JVM内是多个线程同时修改同一个对象的过程。
方法类型 | 抛出异常 | 特殊值 | 阻塞 | 超时 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
移除 | remove() | poll() | take() | poll(time,unit) |
检查 | element() | peek() | 不可用 | 不可用 |
抛出异常
当阻塞队列满时,再往队列里add插入元素会抛IllegalStateException: Queue full
当阻塞队列空时,再往队列里remove移除元素会抛NoSuchElementException
特殊值
插入方法,成功ture失败false
移除方法,成功返回出队列的元素,队列里面没有就返回null
一直阻塞
当阻塞队列满时,生产者线程继续往队列里put元素,队列会一直阻塞生产线程直到put数据or响应中断退出。
当阻塞队列空时,消费者线程试图从队列里take元素,队列会一直阻塞消费者线程直到队列可用。
BlockingQueue<String> b = new ArrayBlockingQueue(2);
System.out.println(b.add("1"));
System.out.println(b.add("2"));
//llegalStateException: Queue full
//System.out.println(b.add("3"));
//在开头的为:1
System.out.println("在开头的为:" + b.element());
//先进先出,先出来 1
System.out.println(b.remove());
System.out.println(b.remove());
//java.util.NoSuchElementException
System.out.println(b.remove());
无界队列:在创建时未指定队列的大小。
ArrayBlockingQueue是有界的 (固定大小)阻塞队列实现,
LinkedBlockingQueue是一个可选的有界阻塞队列实现,
PriorityBlockingQueue是一个可以按特定顺序消费项目,
DelayQueue 队列实现的延迟无界阻塞队列
LinkedTransferQueue提供了实现一种背压形式的能力。
SynchronousQueue提供在线程之间交换数据的简单方法
只有一个不取走,不生产第二个。
Collection
block
n.
大块,一块(木料、石头等);(四面临街的)街段,
v.
阻塞,堵塞(道路、管道等);遮住(视线)
priority
英
/praɪˈɒrəti/
n.
优先事项,最重要的事;优先,优先权,重点;<英>优先通行权
adj.
优先的
synchron ized
synchronous
英
/ˈsɪŋkrənəs/
adj.
同步的;同时的
offer
英
/ˈɒfə(r)/
v.
提供,给予;提议,表示愿意(做某事);出(价),开(价);提出,作出;表示(爱、友谊等);
n.
主动提议,提供; 出价,报价; (商品的)特价,特惠;求婚
poll
n.
民意调查,民意测验;选举投票,计票;投票数;
v.
对……进行民意测验(调查);获得(票数);(电信,计算机)轮询,探询;
peek
英
/piːk/
v.
偷看,窥视;微露出,探出
n.
一瞥,偷偷地一看;(计算机)读取数据
public class PriorityBlockingQueueTest {
public static void main(String[] args) {
//长度10的 排队阻塞队列
PriorityBlockingQueue<Patient> pbq = new PriorityBlockingQueue<>(10);
//创建3个 年轻人,放入
for (int i = 0; i < 3; i++) {
Patient patent = new Patient("Patent" + i, 20 + i);
pbq.offer(patent);
}
//创建一个 年老的人
Patient oldMan = new Patient("OldMan", 88);
pbq.offer(oldMan);
Patient patient = null;
do {
//逐步弹出
patient = pbq.poll();
if (patient != null) {
System.out.println(patient.name + "挂号成功!");
}
} while (patient != null);
}
static class Patient implements Comparable<Patient> {
private String name;
private Integer age;
private long waitingTime;
public Patient(String name, Integer age) {
this.name = name;
this.age = age;
this.waitingTime = System.nanoTime();
}
@Override
public int compareTo(Patient o) {
// 80岁和以上,返回 -1,权限更高
if (age >= 80) {
return -1;
} /*else
if (o.age >= 80) {
return 1;
}*/
//谁先来,谁先执行
return waitingTime < o.waitingTime ? -1 : 1;
}
}
}
DelayQueue 是一个通过PriorityBlockingQueue实现延迟获取元素的无界队列 无界阻塞队列,
DelayQueue可以运用在以下应用场景:
delayTime=3, expire=1680947698428, data=第二次添加任务
delayTime=5, expire=1680947700428, data=第三次添加任务
delayTime=8, expire=1680947703428, data=第一次添加任务
public class DelayQueueDemo {
static BlockingQueue<Delayed> queue = new DelayQueue();
public static void main(String[] args) throws InterruptedException {
queue.add(new MyDelay(8, "第一次添加任务"));
queue.add(new MyDelay(3, "第二次添加任务"));
queue.add(new MyDelay(5, "第三次添加任务"));
while (!queue.isEmpty()) {
Delayed delayed = queue.take();
System.out.println(delayed);
}
}
}
class MyDelay<T> implements Delayed {
long delayTime; // 延迟时间
long expire; // 过期时间
T data;
public MyDelay(long delayTime, T t) {
this.delayTime = delayTime;
// 过期时间 = 当前时间 + 延迟时间
this.expire = System.currentTimeMillis() + delayTime * 1000;
data = t;
}
/**
* 剩余时间 = 到期时间 - 当前时间
*/
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(this.expire - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
/**
* 优先级规则:两个任务比较,时间短的优先执行
*/
@Override
public int compareTo(Delayed o) {
long f = this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS);
return (int) f;
}
@Override
public String toString() {
return "delayTime=" + delayTime +
", expire=" + expire +
", data=" + data;
}
}
LinkedTransferQueue是一个由链表结构组成的无界阻塞TransferQueue队列。相对于其他阻塞队列,LinkedTransferQueue多了tryTransfer和transfer方法。
transfer
v.
(使)转移,搬迁;转移(感情),传染(疾病),转让(权力等);(使)调动,转职;转会
n.
转移,转让,调动;(运动员)转会;转换,过渡;已调动的人,已转移的东西;
LinkedTransferQueue<String> g = new LinkedTransferQueue<String>();
new Thread(() -> {
try {
System.out.println("Transferring" + " an element");
// Transfer a String element
// using transfer() method
g.transfer("is a computer" + " science portal.");
System.out.println("Element " + "transfer is complete");
} catch (InterruptedException e1) {
System.out.println(e1);
} catch (NullPointerException e2) {
System.out.println(e2);
}
}).start();
try {
// Get the transferred element
System.out.println("Geeks for Geeks "+ g.take());
} catch (Exception e) {
System.out.println(e);
}
public static void main(String args[]) {
LinkedTransferQueue<String> g = new LinkedTransferQueue<String>();
new Thread(() -> {
try {
System.out.println("Transferring" + " an element");
// Transfer a null element
// using transfer() method
g.transfer(null);
System.out.println("Element " + "transfer is complete");
} catch (Exception e) {
System.out.println(e);
System.exit(0);
}
}).start();
try {
// Get the transferred element
System.out.println("Geeks for Geeks "
+ g.take());
} catch (Exception e) {
System.out.println(e);
}
}
Transferring an element
java.lang.NullPointerException
tryTransfer(E e)方法
tryTransfer(E e) 当生产者线程调用tryTransfer方法时,如果没有消费者等待接收元素,则会立即返回false。该方法和transfer方法的区别就是tryTransfer方法无论消费者是否接收,方法立即返回,而transfer方法必须等到消费者消费后才返回。
tryTransfer(E e, long timeout, TimeUnit unit) 加上了限时等待功能,如果没有消费者消费该元素,则等待指定的时间再返回;如果超时还没消费元素,则返回false,如果在超时时间内消费了元素,则返回true。
transfer(E e)方法
transfer方法,用于将指定元素e传递给消费者线程(调用take/poll方法)。如果有消费者线程正在阻塞等待,则调用transfer方法的线程会直接将元素传递给它;
如果没有消费者线程等待获取元素,则调用transfer方法的线程会将元素插入到队尾,然后阻塞等待,直到出现一个消费者线程获取元素。
阻塞队列下的没有容量,
进去一个元素,必须等待取出来之后,才能再往里面放一个元素!
put、take
/**
* 同步队列
* 和其他的BlockingQueue 不一样, SynchronousQueue 不存储元素
* put了一个元素,必须从里面先take取出来,否则不能在put进去值!
*/
public class SynchronousQueueDemo {
public static void main(String[] args) {
BlockingQueue<String> blockingQueue = new SynchronousQueue<>(); // 同步队列
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(6);
System.out.println(Thread.currentThread().getName() + " put 1");
blockingQueue.put("1");
System.out.println(Thread.currentThread().getName() + " put 2");
blockingQueue.put("2");
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "T1").start();
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName() + "=>" + blockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "T2").start();
}
}
是一个无界、线程安全且非阻塞的队列。它不是BlockingQueue的实现类。
BlockingQueue的实现类都是阻塞队列。
ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();
queue.offer("哈哈哈");
System.out.println("从队列中peek:" + queue.peek());
System.out.println("offer后,队列是否空?" + queue.isEmpty());
System.out.println("从队列中poll:" + queue.poll());
System.out.println("从队列中peek:" + queue.peek());
System.out.println("pool后,队列是否空?" + queue.isEmpty());
从队列中peek:哈哈哈
offer后,队列是否空?false
从队列中poll:哈哈哈
从队列中peek:null
pool后,队列是否空?true