爬梯:JUC并发编程(一)
学习资源整理自: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并发编程(一)相关推荐
- 爬梯:JUC并发编程(三)
学习资源整理自:B站<狂神说> 书接上回 JUC并发编程 12.CompletableFuture 异步回调 理解 父类:Future,对将来的某个事件的结果进行建模 可以用ajax进行理 ...
- 爬梯:JUC并发编程(二)
学习资源整理自:B站<狂神说> 书接上回 JUC并发编程 8.线程池(重点) 线程池:三大方法.七大参数.四种拒绝策略 池化技术 程序的执行,本质:占用系统的资源!优化资源的使用==> ...
- 【尚硅谷】大厂必备技术之JUC并发编程——笔记总结
[JUC并发编程01]JUC概述 关键字:进程和线程.进程和线程.wait和sleep.并发与并行.管程.用户线程和守护线程 [JUC并发编程02]Lock接口 关键字:synchronized.Lo ...
- JUC并发编程中的集合不安全问题源码解析
JUC并发编程四:集合不安全(Java) 1.List不安全! 代码示例: package unsafe;import java.util.*; import java.util.concurrent ...
- ❤️《JUC并发编程从入门到高级》(建议收藏)❤️
JUC并发编程 1.什么是JUC JUC的意思就是java并发编程工具包,与JUC相关的有三个包:java.util.concurrent.java.util.concurrent.atomic.ja ...
- 厚积薄发打卡Day26:狂神说Java之JUC并发编程<代码+笔记>(上)
前言: 学习视频来源:[狂神说Java]JUC并发编程最新版通俗易懂 一个十分优秀且励志的技术大牛+Java讲师,十分推荐他的频道:遇见狂神说
- JUC并发编程第十四篇,StampedLock(邮戳锁)为什么比ReentrantReadWriteLock(读写锁)更快!
JUC并发编程第十四篇,StampedLock(邮戳锁)为什么比ReentrantReadWriteLock(读写锁)更快! 一.ReentrantReadWriteLock(读写锁) 1.读写锁存在 ...
- 多线程进阶=》JUC并发编程02
在JUC并发编程01中说到了,什么是JUC.线程和进程.Lock锁.生产者和消费者问题.8锁现象.集合类不安全.Callable(简单).常用辅助类.读写锁 https://blog.csdn.net ...
- 基于《狂神说Java》JUC并发编程--学习笔记
前言: 本笔记仅做学习与复习使用,不存在刻意抄袭. -------------------------------------------------------------------------- ...
最新文章
- 计算机图形学——BRDF
- javascript进制转换_44道JavaScript送命题
- Django学习记录-1
- 初中学历怎么学计算机管理,初中学历能否学习计算机
- hdu 2136 筛法求素数
- JQuery 动态生成元素添加点击事件
- 【转】2007高校BBS上20个睿智的冷笑话
- 交互式内核图 -***
- LeetCode-144:二叉树的前序遍历
- 网站制作---eWebeditor不兼容IE8问题的解决方法
- Android NDK 【错误】The method loadLibrary(String) is undefined for the type Settings.Syste
- Splunk数据处理
- maven pom聚合与继承
- mysql外键必须连接主键_MySQL数据库的主键和外键详解3
- ArrayList LinkedList
- 评选最佳文本编辑器-UltraEdit From善用佳软
- 风云2号卫星云图_中国为什么要发这么多卫星?答案没有出乎意料
- [转]Unicode汉字编码表
- LeetCode114--词典中最长的单词、最短补全词、宝石与石头
- 硬盘位置不可用因格式变RAW而打不开:文件或目录损坏且无法读取/此卷不包含可识别的文件系统等无法访问错误-CHKDSK被中止
热门文章
- 考研笔记:有关片选信号逻辑表达式求解的探究
- Java架构-别忽视分布式系统这六大“暗流”
- clickhouse做漏斗分析
- SCADA系统全面介绍
- 初识 hessian--helloworld
- android 来电拒接_android-如何拒绝/关闭特定的来电号码
- 妖人柴:网络赚钱,想倍增收入,你有绝活吗?
- mitmproxy+appium实现抖音关键字搜索结果自动获取,抖音爬虫
- 怀疑开发者在“造核弹”?GitHub不断封禁开源项目
- 【板栗糖GIS】arcmap—如何使属性表中的数值四舍五入保留两位小数