学习资源整理自:B站《狂神说》

JUC并发编程

1、基础概念

JUC 就是 java.util.concurrent

java到底能否自己开启线程?
答案是否定的,在创建线程的底层,使用的是本地方法,也就是说是使用C++创建的

并发、并行

并发(多线程操作同一个资源)

  • CPU单核,模拟出多条线程,快速切换

并行(多线程同行)

  • CPU多核,同事执行:线程池
//获取CPU的核数
//CPU密集型、IO密集型
Runtime.getRuntime().availableProcessors();

并发编程的本质:充分利用CPU资源

线程状态

源码:

public enum State {//新生NEW,//运行RUNNABLE,//阻塞BLOCKED,//一直等待WAITING,//指定时间等待TIMED_WAITING,//终止TERMINATED;
}

wait/sleep的异同

1、来自不同的类
wait—>Object
sleep—>Thread
2、关于锁的释放
wait会释放锁,sleep不会施放锁(抱着锁睡觉)
3、使用范围
wait 必须在同步代码块中使用
sleep 可以在任何地方
4、捕获异常
wait不需要捕获异常
sleep必须要捕获异常

2、Lock锁(重点)

真正的多线程开发,线程就是一个单独的资源类,没有附属操作。

1、属性、方法

传统synchronized

代码实现:

/*** 原始方式synchronized实现并发* @author: stone* @create: 2020-08-15 14:30*/
public class Test01 {public static void main(String args[]){//创建资源类实例,实现并发:多线程操作同一个资源Tickets tickets = new Tickets();//实现并发 买票new Thread(()->{for (int i = 0; i < 40; i++) {tickets.saleTicket();}},"小石").start();new Thread(()->{for (int i = 0; i < 40; i++) {tickets.saleTicket();}},"小杰").start();new Thread(()->{for (int i = 0; i < 40; i++) {tickets.saleTicket();}},"小伦").start();}
}
/*** 资源类* 只含有属性、方法*/
class Tickets{int ticketCount = 30;public synchronized void saleTicket(){if(ticketCount>0){System.out.println(Thread.currentThread().getName()+"买到一张票,剩余"+ticketCount--);}}
}

ReentrantLock

源码

FairSync:公平锁,先来后到

NonfairSync:非公平锁,可以插队(默认)

为什么默认是非公平锁呢?

因为有的线程执行完需要1个小时,而有些线程需要1分钟,为了“公平”可以允许:先执行1分钟,再执行1小时的情况

代码实现:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** JUC ReentrantLock* @author: stone* @create: 2020-08-15 15:01*/
public class Test02 {public static void main(String args[]){//创建资源类实例,实现并发:多线程操作同一个资源Tickets tickets = new Tickets();new Thread(()-> { for (int i = 0; i < 40; i++) tickets.saleTicket();},"小石").start();new Thread(()-> { for (int i = 0; i < 40; i++) tickets.saleTicket();},"小杰").start();new Thread(()-> { for (int i = 0; i < 40; i++) tickets.saleTicket();},"小伦").start();}
}/*** Lock的三个步骤* 1、new ReentrantLock()* 2、lock.lock()* 3、lock.unlock()*/
class Tickets2{int ticketCount = 30;//创建可重入锁Lock lock = new ReentrantLock();public void saleTicket(){lock.lock();//加锁try {if(ticketCount>0){System.out.println(Thread.currentThread().getName()+"买到一张票,剩余"+ticketCount--);}}catch (Exception e){}finally {lock.unlock();//解锁}}
}

Synchronized和Lock的区别

Synchronized Lock
java内置关键字 java的一个类
无法获取锁的状态 可以判断是否获取到了锁
自动释放锁 必须手动施放锁
若A获得锁后造成死锁,B将一直等待 拥有tryLock()方法,可以尝试获得锁
可重入锁,不可以中断的非公平锁 可重入锁,可以判断锁,可以设置公平锁或非公平锁
适合锁少量代码同步 适合锁大量代码同步

3、生产者和消费者场景

synchronized代码实现:

/*** synchronized实现生产者消费者通信* @author: stone* @create: 2020-08-15 16:00*/
public class TestSychronized {public static void main(String args[]){Product product = new Product();//资源//生产线程new Thread(()->{for (int i = 0; i < 10; i++) {try {product.increment();} catch (InterruptedException e) {e.printStackTrace();}}},"小石1").start();//生产线程new Thread(()->{for (int i = 0; i < 10; i++) {try {product.increment();} catch (InterruptedException e) {e.printStackTrace();}}},"小石2").start();//消费线程new Thread(()->{for (int i = 0; i < 10; i++) {try {product.decrement();} catch (InterruptedException e) {e.printStackTrace();}}},"阿伦1").start();//消费线程new Thread(()->{for (int i = 0; i < 10; i++) {try {product.decrement();} catch (InterruptedException e) {e.printStackTrace();}}},"阿伦2").start();}
}class Product{int pCount = 0;//加仓public synchronized void increment() throws InterruptedException {while(pCount!=0){this.wait();//等待,让消费者先消费掉产品}System.out.println(Thread.currentThread().getName()+" 生产了!当前库存:"+ ++pCount);this.notifyAll();//解除消费者的等待}//减仓public synchronized void decrement() throws InterruptedException {while(pCount==0){this.wait();//等待,让生产者先生产}System.out.println(Thread.currentThread().getName()+" 消费了!当前库存:"+ --pCount);this.notifyAll();//解除生产者的等待}
}

结果:

小石1 生产了!当前库存:1
阿伦1 消费了!当前库存:0
小石2 生产了!当前库存:1
阿伦1 消费了!当前库存:0
小石1 生产了!当前库存:1
阿伦1 消费了!当前库存:0
小石2 生产了!当前库存:1
阿伦1 消费了!当前库存:0
小石1 生产了!当前库存:1
阿伦1 消费了!当前库存:0
小石2 生产了!当前库存:1
阿伦2 消费了!当前库存:0
......

如上while处,是因为有个“虚拟唤醒”的概念。

虚拟唤醒

当别的线程调用notifyAll之后,唤醒了全部等待的线程,而有的线程唤醒了之后,还没有真实轮到他干活(比如,当前pCount=1是需要生产的,但是他被唤醒干活了,这就叫做虚拟唤醒),常因为使用了if作为判断条件时产生,所以需要循环去判断:当线程被唤醒时:是否真的轮到我干活了?不然我继续等待~

JUC代码实现:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** JUC 实现生产者消费者通信* @author: stone* @create: 2020-08-15 17:00*/
public class TestJUC {public static void main(String args[]){Product2 product = new Product2();//资源//生产线程new Thread(()->{for (int i = 0; i < 10; i++) {try {product.increment();} catch (InterruptedException e) {e.printStackTrace();}}},"小石1").start();//生产线程new Thread(()->{for (int i = 0; i < 10; i++) {try {product.increment();} catch (InterruptedException e) {e.printStackTrace();}}},"小石2").start();//消费线程new Thread(()->{for (int i = 0; i < 10; i++) {try {product.decrement();} catch (InterruptedException e) {e.printStackTrace();}}},"阿伦1").start();//消费线程new Thread(()->{for (int i = 0; i < 10; i++) {try {product.decrement();} catch (InterruptedException e) {e.printStackTrace();}}},"阿伦2").start();}
}class Product2{int pCount = 0;Lock lock = new ReentrantLock();Condition condition = lock.newCondition();//取代原监视器的方法(wait.notify.notifyAll)//加仓public void increment() throws InterruptedException {lock.lock();try {while(pCount!=0){condition.await();//等待,让消费者先消费掉产品}System.out.println(Thread.currentThread().getName()+" 生产了!当前库存:"+ ++pCount);condition.signalAll();//解除消费者的等待} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}//减仓public void decrement() throws InterruptedException {lock.lock();try {while(pCount==0){condition.await();//等待,让生产者先生产}System.out.println(Thread.currentThread().getName()+" 消费了!当前库存:"+ --pCount);condition.signalAll();//解除生产者的等待} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}
}

结果:

小石1 生产了!当前库存:1
阿伦1 消费了!当前库存:0
小石1 生产了!当前库存:1
阿伦1 消费了!当前库存:0
小石2 生产了!当前库存:1
阿伦2 消费了!当前库存:0
小石2 生产了!当前库存:1
阿伦2 消费了!当前库存:0
小石2 生产了!当前库存:1
阿伦2 消费了!当前库存:0
小石2 生产了!当前库存:1
阿伦2 消费了!当前库存:0
......

JUC实现精准唤醒:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** JUC Condition实现精准唤醒* @author: stone* @create: 2020-08-16 13:27*/
public class TestJUC2 {public static void main(String args[]){Product3 product = new Product3();//资源new Thread(()->{for (int i = 0; i < 10; i++) {try {product.fun1();} catch (InterruptedException e) {e.printStackTrace();}}},"石").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {product.fun2();} catch (InterruptedException e) {e.printStackTrace();}}},"似").start();//消费线程new Thread(()->{for (int i = 0; i < 10; i++) {try {product.fun3();} catch (InterruptedException e) {e.printStackTrace();}}},"心").start();}
}class Product3{int num = 0;Lock lock = new ReentrantLock();Condition condition1 = lock.newCondition();//取代原监视器的方法(wait.notify.notifyAll)Condition condition2 = lock.newCondition();//取代原监视器的方法(wait.notify.notifyAll)Condition condition3 = lock.newCondition();//取代原监视器的方法(wait.notify.notifyAll)public void fun1() throws InterruptedException {lock.lock();try {while(num!=0){condition1.await();//等待}System.out.println(num++ +"==="+Thread.currentThread().getName()+"===");condition2.signal();//解除指定的监控器条件器} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void fun2() throws InterruptedException {lock.lock();try {while(num!=1){condition2.await();//等待}System.out.println(num++ +"==="+Thread.currentThread().getName()+"===");condition3.signal();//解除指定的监控器条件器} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}public void fun3() throws InterruptedException {lock.lock();try {while(num!=2){condition3.await();//等待}System.out.println(num +"==="+Thread.currentThread().getName()+"===");num=0;condition1.signal();//解除指定的监控器条件器} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}
}

结果:

0===石===
1===似===
2===心===
0===石===
1===似===
2===心===
0===石===
1===似===
2===心===
......

4、8锁现象

关于锁的8个问题

1、先执行哪个方法?为什么?(锁的对象)

import java.util.concurrent.TimeUnit;/*** 8锁现象* @author: stone* @create: 2020-08-16 13:46*/
public class Test1 {public static void main(String args[]){Cup cup = new Cup();new Thread(()->{cup.takeInWater();},"A").start();try {//延迟500毫秒TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}new Thread(()->{cup.pourWater();},"B").start();}
}/*** 水杯*/
class Cup{public synchronized void takeInWater(){System.out.println("装水--");}public synchronized void pourWater(){System.out.println("倒水--");}
}

完美回答:

​ 装水方法先执行,因为主线程上有调用sleep方法,让主线程挂起500毫秒,再启动B线程执行倒水的方法,此时A线程先获得cup对象的锁。(回答先后顺序的答案都不对)

2、当装水方法延迟2秒,哪个线程先执行?

//主方法同上/*** 水杯*/
class Cup{public synchronized void takeInWater(){try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("装水--");}public synchronized void pourWater(){System.out.println("倒水--");}
}

完美回答:

​ 装水方法先执行,因为装水方法想获得cup对象的锁,执行了sleep方法,锁住对象挂起等待,所以需要装水方法执行完才能执行倒水方法。

3、增加一个普通方法后,先执行哪个线程?

public class Test1 {public static void main(String args[]){Cup cup = new Cup();new Thread(()->{cup.takeInWater();},"A").start();try {//延迟500毫秒TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}new Thread(()->{cup.washCup();},"B").start();}
}/*** 水杯*/
class Cup{public synchronized void takeInWater(){try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("装水--");}public synchronized void pourWater(){System.out.println("倒水--");}public void washCup(){System.out.println("洗杯子--");}
}

完美回答:

​ 先执行洗杯子方法,因为洗杯子是普通方法,不是同步代码,不受锁限制。

4、两个对象的情况下,哪个线程先执行,为什么?

/*** @author: stone* @create: 2020-08-16 14:23*/
public class Test4 {public static void main(String args[]){Cup4 cup1 = new Cup4();Cup4 cup2 = new Cup4();new Thread(()->{cup1.takeInWater();},"A").start();try {//延迟500毫秒TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}new Thread(()->{cup2.pourWater();},"B").start();}
}/*** 水杯*/
class Cup4{public synchronized void takeInWater(){try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("装水--");}public synchronized void pourWater(){System.out.println("倒水--");}
}

完美答案:

​ 先执行倒水方法,两个对象就有两个锁,互不影响。

5、静态同步方法,哪个线程先执行?

public class Test5 {public static void main(String args[]){Cup5 cup1 = new Cup5();new Thread(()->{cup1.takeInWater();},"A").start();try {//延迟500毫秒TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}new Thread(()->{cup1.pourWater();},"B").start();}
}/*** 水杯*/
class Cup5{public static synchronized void takeInWater(){try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("装水--");}public static synchronized void pourWater(){System.out.println("倒水--");}
}

完美答案:

​ 装水方法先执行,先获得锁的对象先执行,而且static修饰的方法是在类加载的时候生成的,也就在class文件中,所以此时的锁是所在了class对象上。(若只回答先获得锁先执行则不能得全分)

6、两个对象的情况下,静态同步方法,哪个先执行?

public static void main(String args[]){Cup6 cup1 = new Cup6();Cup6 cup2 = new Cup6();new Thread(()->{cup1.takeInWater();},"A").start();try {//延迟500毫秒TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}new Thread(()->{cup2.pourWater();},"B").start();
}//资源类代码同上

完美答案:

​ 装水方法先执行,因为静态方法上的锁是锁在了class对象上,全局唯一。

7、一个静态同步方法和一个普通同步方法,哪个先执行?

public class Test7 {public static void main(String args[]){Cup7 cup1 = new Cup7();new Thread(()->{cup1.takeInWater();},"A").start();try {//延迟500毫秒TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}new Thread(()->{cup1.pourWater();},"B").start();}
}/*** 水杯*/
class Cup7{public static synchronized void takeInWater(){try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("装水--");}public synchronized void pourWater(){System.out.println("倒水--");}
}

完美答案:

​ 先执行倒水方法,因为倒水方法的锁锁的是对象,而装水锁的是class类模板,

8、两个对象,一个调用静态同步方法,一个调用同步方法,哪个先执行?

public static void main(String args[]){Cup8 cup1 = new Cup8();Cup8 cup2 = new Cup8();new Thread(()->{cup1.takeInWater();},"A").start();try {//延迟500毫秒TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}new Thread(()->{cup2.pourWater();},"B").start();
}
//资源类代码同上

完美答案:

​ 先执行倒水方法,因为倒水方法锁的是对象,不需要等待class类模板施放锁。

3、集合类线程不安全

List

/*** 集合类不安全* java.util.ConcurrentModificationException 并发修改异常* @author: stone* @create: 2020-08-16 16:29*/
public class TestList {public static void main(String args[]){/*** 并发下的ArrayList不安全* 解决方案:* 1、List<String> list = new Vector<String>(); 查看Vector.add()源码得知,add方法由synchronized修饰* 2、List<String> list = Collections.synchronizedList(new ArrayList<>()); 使用集合工具类,创建线程安全的ArrayList* 3、List<String> list = new CopyOnWriteArrayList<String>();*///  CopyOnWrite 写入时复制  COW 计算机程序设计领域的一种优化策略:// 在写入是复制一份出来写入,写入完再复制回原来的数组里,避免写入时覆盖造成数据问题!List<String> list = new CopyOnWriteArrayList<String>();for (int i = 0; i < 10; i++) {//十个线程去修改listnew Thread(()->{list.add(UUID.randomUUID().toString().substring(0,5));System.out.println(list);},String.valueOf(i)).start();}}
}

源码:

Set

/*** Set 线程不安全 java.util.ConcurrentModificationException* @author: stone* @create: 2020-08-16 17:16*/
public class TestSet {public static void main(String args[]){/*** 并发下的HashSet不安全* 解决方案:* 1、Set<String> set = Collections.synchronizedSet(new HashSet<>()); 使用集合工具类* 2、Set<String> set = new CopyOnWriteArraySet<String>();*/Set<String> set = new CopyOnWriteArraySet<String>();for (int i = 0; i < 30; i++) {new Thread(()->{set.add(UUID.randomUUID().toString().substring(0,5));System.out.println(set);},String.valueOf(i)).start();}}
}

Set基础补充:

Set和List一样,继承自Collection

源码:



所以HashSet底层就是一个MashMap的key,没有value

无序不重复

HashMap

/*** Map 线程不安全 java.util.ConcurrentModificationException* @author: stone* @create: 2020-08-16 17:35*/
public class TestMap {public static void main(String args[]){Map<String,String> map = new ConcurrentHashMap<String,String>();for (int i = 0; i < 30; i++) {new Thread(()->{map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,5));System.out.println(map);},String.valueOf(i)).start();}}
}

4、Callable

官方文档:

细节:1、有缓存;2、等待结果时会阻塞;

代码实现:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;/*** 使用Callable* 相比Runnable,Callable能抛出异常,并且有返回值* @author: stone* @create: 2020-08-16 17:59*/
public class TestCallable {public static void main(String args[]) throws ExecutionException, InterruptedException {MyThread myThread = new MyThread();FutureTask<String> futureTask = new FutureTask(myThread);//适配器new Thread(futureTask,"A").start();//结果会被写入缓存TimeUnit.SECONDS.sleep(1);new Thread(futureTask,"B").start();System.out.println(futureTask.get());//执行耗时任务时,可能会阻塞}
}class MyThread implements Callable<String>{@Overridepublic String call() throws Exception {System.out.println(Thread.currentThread().getName()+" call()");return "re call";}
}

打印结果:

5、常用辅助类

CountDownLatch

计数器,官方文档:

代码实现:

public static void main(String args[]) throws InterruptedException {/*** 计数器,初始化时给定一个统计数* 在需要某些任务必须完成时使用,设置成必须倒数完,主流程才能继续走下去*/CountDownLatch countDownLatch = new CountDownLatch(5);for (int i = 0; i < 5; i++) {new Thread(()->{System.out.println(Thread.currentThread().getName());countDownLatch.countDown();//-1},String.valueOf(i)).start();}countDownLatch.await();//等待计数器倒数完毕System.out.println("主流程任务--");
}

控制台:

0
1
4
3
2
主流程任务--Process finished with exit code 0

CyclicBarrier

代码实现:

public static void main(String args[]){CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{System.out.println("集齐七颗龙珠召唤神龙!~");});for (int i = 1; i <= 7 ; i++) {new Thread(()->{System.out.println("收集到第"+Thread.currentThread().getName()+"颗龙珠");try {//设置屏障点,需要等全部线程走到这一步才能继续执行cyclicBarrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}},String.valueOf(i)).start();}
}

控制台:

收集到第1颗龙珠
收集到第3颗龙珠
收集到第2颗龙珠
收集到第4颗龙珠
收集到第5颗龙珠
收集到第6颗龙珠
收集到第7颗龙珠
集齐七颗龙珠召唤神龙!~Process finished with exit code 0

Semaphore

信号量

官方文档:

代码实现:

public static void main(String args[]){/*** 模拟抢车位场景、限流* 只有3个车位,但是有7台车,轮流停车*/Semaphore semaphore = new Semaphore(3);for (int i = 1; i <= 7; i++) {new Thread(()->{try {semaphore.acquire();//线程进入,获取System.out.println(Thread.currentThread().getName()+"进入停车位》》》》");TimeUnit.SECONDS.sleep(1);//停车1s} catch (InterruptedException e) {e.printStackTrace();}finally {System.out.println(Thread.currentThread().getName()+"离开停车位《《《《");semaphore.release();//线程执行完毕,施放信号}},String.valueOf(i)).start();}
}

控制台:

3进入停车位》》》》
1进入停车位》》》》
2进入停车位》》》》
2离开停车位《《《《
3离开停车位《《《《
1离开停车位《《《《
6进入停车位》》》》
4进入停车位》》》》
5进入停车位》》》》
6离开停车位《《《《
4离开停车位《《《《
5离开停车位《《《《
7进入停车位》》》》
7离开停车位《《《《Process finished with exit code 0

acquire():获取,若信号量满了的时候则挂起等待。

release():释放,当前线程执行完毕,释放信号。

6、读写锁

官方文档:

写锁:一次只能被一个线程占有;

读锁:多个线程可以同时占有;

代码实现:

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;/*** @author: stone* @create: 2020-08-16 22:27*/
public class readWriteLockDemo {public static void main(String args[]){MyCacheLock myCacheLock = new MyCacheLock();//资源类//模拟5个写入线程for (int i = 1; i <= 5 ; i++) {final int tempI = i;new Thread(()->{myCacheLock.write(String.valueOf(tempI),"石似心"+tempI);}).start();}//模拟5个读取线程for (int i = 1; i <= 5 ; i++) {final int tempI = i;new Thread(()->{myCacheLock.read(String.valueOf(tempI));}).start();}}
}
class MyCacheLock {private volatile Map<String,Object> map = new HashMap<>();//读写锁:相较于普通的可重入锁,细粒度更高,读写分开控制ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();public void write(String key,Object value){readWriteLock.writeLock().lock();//加写锁try {System.out.println(Thread.currentThread().getName()+"写入"+key);map.put(key,value);System.out.println(Thread.currentThread().getName()+"写入完毕。。。");} catch (Exception e) {e.printStackTrace();} finally {readWriteLock.writeLock().unlock();//释放}}public void read(String key){readWriteLock.readLock().lock();//加读锁try {System.out.println(Thread.currentThread().getName()+"读取"+key);map.get(key);System.out.println(Thread.currentThread().getName()+"读取完毕。。。");} catch (Exception e) {e.printStackTrace();} finally {readWriteLock.readLock().unlock();//释放}}
}

7、阻塞队列

BlockingQueue

家族关系:

什么情况下使用阻塞队列:多线程并发处理,线程池。

四组API:

方式 抛出异常 返回值 阻塞等待 超时等待
添加 add offer put offer(val,time,unit)
移除 remove poll take poll(time,unit)
检测队首 element peek
抛出异常
/**
* 抛出异常 add remove
*/
public static void test1(){ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(2);System.out.println(arrayBlockingQueue.add("A"));System.out.println(arrayBlockingQueue.add("B"));/*Exception in thread "main" java.lang.IllegalStateException: Queue full*///System.out.println(arrayBlockingQueue.add("C")); //System.out.println("--------------------------------------");/*检测队首元素,返回 A */System.out.println(arrayBlockingQueue.element());System.out.println("--------------------------------------");/*先进先出*/System.out.println(arrayBlockingQueue.remove());System.out.println(arrayBlockingQueue.remove());/*Exception in thread "main" java.util.NoSuchElementException*///System.out.println(arrayBlockingQueue.remove());}
返回值
/*** 有返回值,无异常*/
public static void test2(){ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(2);System.out.println(arrayBlockingQueue.offer("A"));System.out.println(arrayBlockingQueue.offer("B"));/*超出队列范围,返回false,不会报错 */System.out.println(arrayBlockingQueue.offer("C"));System.out.println("--------------------------------------");/*检测队首元素 返回A* 若无则返回 null 不会报错*/System.out.println(arrayBlockingQueue.peek());System.out.println("--------------------------------------");/*先进先出*/System.out.println(arrayBlockingQueue.poll());System.out.println(arrayBlockingQueue.poll());/*超出队列范围,返回null,不会报错*/System.out.println(arrayBlockingQueue.poll());
}
阻塞等待
/*** 阻塞 等待*/
public static void test3() throws InterruptedException {ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(2);arrayBlockingQueue.put("A");arrayBlockingQueue.put("B");/*超出队列范围: 阻塞线程,一直等待,不会报错没有返回值 *///arrayBlockingQueue.put("C");System.out.println("--------------------------------------");/*先进先出*/System.out.println(arrayBlockingQueue.take());System.out.println(arrayBlockingQueue.take());/*超出队列范围: 阻塞线程,一直等待,不会报错没有返回值*/System.out.println(arrayBlockingQueue.take());
}
超时等待
/*** 超时 等待*/
public static void test4() throws InterruptedException {ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(2);System.out.println(arrayBlockingQueue.offer("A"));System.out.println(arrayBlockingQueue.offer("B"));/*超出队列范围: 阻塞线程,两秒内若仍无位置,则施放线程,返回false */System.out.println(arrayBlockingQueue.offer("C", 2, TimeUnit.SECONDS));System.out.println("--------------------------------------");/*先进先出*/System.out.println(arrayBlockingQueue.poll());System.out.println(arrayBlockingQueue.poll());/*超出队列范围: 阻塞线程,一直等待,不会报错没有返回值*/System.out.println(arrayBlockingQueue.poll(2, TimeUnit.SECONDS));
}

篇幅太长,拆分下一篇

爬梯:JUC并发编程(一)相关推荐

  1. 爬梯:JUC并发编程(三)

    学习资源整理自:B站<狂神说> 书接上回 JUC并发编程 12.CompletableFuture 异步回调 理解 父类:Future,对将来的某个事件的结果进行建模 可以用ajax进行理 ...

  2. 爬梯:JUC并发编程(二)

    学习资源整理自:B站<狂神说> 书接上回 JUC并发编程 8.线程池(重点) 线程池:三大方法.七大参数.四种拒绝策略 池化技术 程序的执行,本质:占用系统的资源!优化资源的使用==> ...

  3. 【尚硅谷】大厂必备技术之JUC并发编程——笔记总结

    [JUC并发编程01]JUC概述 关键字:进程和线程.进程和线程.wait和sleep.并发与并行.管程.用户线程和守护线程 [JUC并发编程02]Lock接口 关键字:synchronized.Lo ...

  4. JUC并发编程中的集合不安全问题源码解析

    JUC并发编程四:集合不安全(Java) 1.List不安全! 代码示例: package unsafe;import java.util.*; import java.util.concurrent ...

  5. ❤️《JUC并发编程从入门到高级》(建议收藏)❤️

    JUC并发编程 1.什么是JUC JUC的意思就是java并发编程工具包,与JUC相关的有三个包:java.util.concurrent.java.util.concurrent.atomic.ja ...

  6. 厚积薄发打卡Day26:狂神说Java之JUC并发编程<代码+笔记>(上)

    前言: 学习视频来源:[狂神说Java]JUC并发编程最新版通俗易懂 一个十分优秀且励志的技术大牛+Java讲师,十分推荐他的频道:遇见狂神说

  7. JUC并发编程第十四篇,StampedLock(邮戳锁)为什么比ReentrantReadWriteLock(读写锁)更快!

    JUC并发编程第十四篇,StampedLock(邮戳锁)为什么比ReentrantReadWriteLock(读写锁)更快! 一.ReentrantReadWriteLock(读写锁) 1.读写锁存在 ...

  8. 多线程进阶=》JUC并发编程02

    在JUC并发编程01中说到了,什么是JUC.线程和进程.Lock锁.生产者和消费者问题.8锁现象.集合类不安全.Callable(简单).常用辅助类.读写锁 https://blog.csdn.net ...

  9. 基于《狂神说Java》JUC并发编程--学习笔记

    前言: 本笔记仅做学习与复习使用,不存在刻意抄袭. -------------------------------------------------------------------------- ...

最新文章

  1. 计算机图形学——BRDF
  2. javascript进制转换_44道JavaScript送命题
  3. Django学习记录-1
  4. 初中学历怎么学计算机管理,初中学历能否学习计算机
  5. hdu 2136 筛法求素数
  6. JQuery 动态生成元素添加点击事件
  7. 【转】2007高校BBS上20个睿智的冷笑话
  8. 交互式内核图 -***
  9. LeetCode-144:二叉树的前序遍历
  10. 网站制作---eWebeditor不兼容IE8问题的解决方法
  11. Android NDK 【错误】The method loadLibrary(String) is undefined for the type Settings.Syste
  12. Splunk数据处理
  13. maven pom聚合与继承
  14. mysql外键必须连接主键_MySQL数据库的主键和外键详解3
  15. ArrayList LinkedList
  16. 评选最佳文本编辑器-UltraEdit From善用佳软
  17. 风云2号卫星云图_中国为什么要发这么多卫星?答案没有出乎意料
  18. [转]Unicode汉字编码表
  19. LeetCode114--词典中最长的单词、最短补全词、宝石与石头
  20. 硬盘位置不可用因格式变RAW而打不开:文件或目录损坏且无法读取/此卷不包含可识别的文件系统等无法访问错误-CHKDSK被中止

热门文章

  1. 考研笔记:有关片选信号逻辑表达式求解的探究
  2. Java架构-别忽视分布式系统这六大“暗流”
  3. clickhouse做漏斗分析
  4. SCADA系统全面介绍
  5. 初识 hessian--helloworld
  6. android 来电拒接_android-如何拒绝/关闭特定的来电号码
  7. 妖人柴:网络赚钱,想倍增收入,你有绝活吗?
  8. mitmproxy+appium实现抖音关键字搜索结果自动获取,抖音爬虫
  9. 怀疑开发者在“造核弹”?GitHub不断封禁开源项目
  10. 【板栗糖GIS】arcmap—如何使属性表中的数值四舍五入保留两位小数