1.队列: 先到先得的一种数据结构 FIFO
2.阻塞队列:
当阻塞对类为空的时候,从队列中取元素的操作会被阻塞
当阻塞队列为满的时候,往队列中添加元素会被阻塞
当A线程取出队列中元素使的队列变成未满状态,B线程就可以往队列中添加元素
当A线程向队列中添加元素使的队列变非空状态,B线程就可以从队列中取出元素
阻塞队列可以过数据结构控制了线程的阻塞和唤醒
阻塞队列接口和实现类
Queue-->BlockingQueue-->各个实现类
ArrayBlockingQueue(10);//由数组组成的有界阻塞队列
LinkedBlockingDeque();//由链表组成的有界阻塞队列(默认Integer.MAX_VALUE 长度)
PriorityBlockingQueue(;//支持优先级排序的无界阻塞队列
DelayQueue();//使用优先级排序的延时阻塞队列
SynchronousQueue();//单个元素的队列
LinkedTransferQueue();//有链表组成的无界阻塞队列
LinkedBlockingDeque();//有链表组成的双向阻塞队列
api有以下类型
抛出异常 返回boolean组
package com.queue; import java.util.concurrent.*; /** * @author liuxu * @date 2021/11/14 9:11 */ public class MyQueue { public static void main(String[] args) { ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue(3);//由数组组成的有界阻塞队列 arrayBlockingQueue.add("1"); arrayBlockingQueue.add("3"); boolean add = arrayBlockingQueue.add("3"); System.out.println("add=>>"+add+"arrayBlockingQueue size"+arrayBlockingQueue.size()); try { arrayBlockingQueue.add("3"); }catch (Exception e){ System.out.println("超出指定容量抛异常"); } arrayBlockingQueue.remove();//先进先出取出 String remove = arrayBlockingQueue.remove(); System.out.println("remove==》"+remove); arrayBlockingQueue.remove("3");//取出指定 try { arrayBlockingQueue.remove(); }catch (Exception e){ System.out.println("无元素取值抛异常"); } System.out.println("add romve 抛出异常组"); arrayBlockingQueue.offer("1"); arrayBlockingQueue.offer("2"); boolean offer = arrayBlockingQueue.offer("3"); boolean offer1 = arrayBlockingQueue.offer("4"); System.out.println("offer==》"+offer+"offer1==》"+offer1); arrayBlockingQueue.poll(); arrayBlockingQueue.poll(); String poll =arrayBlockingQueue.poll(); String poll1 = arrayBlockingQueue.poll(); System.out.println("poll==》"+poll+"poll1==》"+poll1+" poll无入参,不可取出指定元素,只能FIFO,offer 返回boolean poll无值返回空"); } }
阻塞组
package com.queue; import java.util.concurrent.ArrayBlockingQueue; /** * @author liuxu * @date 2021/11/14 9:47 */ public class MyQueueDlay { public static void main(String[] args) { ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue(3);//由数组组成的有界阻塞队列 try { arrayBlockingQueue.put("1"); arrayBlockingQueue.put("1"); arrayBlockingQueue.put("1"); System.out.println("---------"); arrayBlockingQueue.put("1"); } catch (InterruptedException e) { e.printStackTrace(); } } }
等待一定时间组 与peek element
package com.queue; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit; /** * @author liuxu * @date 2021/11/14 9:52 */ public class QueueTime { public static void main(String[] args) { ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue(3); try { arrayBlockingQueue.offer("1",1, TimeUnit.SECONDS); arrayBlockingQueue.offer("1",1, TimeUnit.SECONDS); arrayBlockingQueue.offer("1",1, TimeUnit.SECONDS); String peek = arrayBlockingQueue.peek(); System.out.println("peek=>>"+peek+" arrayBlockingQueue "+arrayBlockingQueue); String element = arrayBlockingQueue.element(); System.out.println("element=>>"+element+" arrayBlockingQueue"+arrayBlockingQueue); System.out.println("--------------------------------------"); arrayBlockingQueue.offer("1",1, TimeUnit.SECONDS); System.out.println("--------------------------------------"); arrayBlockingQueue.clear(); String peek1 = arrayBlockingQueue.peek(); try { String element1 = arrayBlockingQueue.element(); }catch (Exception e){ System.out.println("element 检查为空抛异常"); } } catch (InterruptedException e) { e.printStackTrace(); } } }
SynchronousQueue只有取出才能存入,用阻塞组api实现控制线程交替输出
package com.queue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; /** * @author liuxu * @date 2021/11/14 10:04 */ public class SyncBlockingQueueDemo { public static void main(String[] args) { BlockingQueue queue = new SynchronousQueue(); new Thread(()->{ try { System.out.println(Thread.currentThread().getName()+" put 1"); queue.put("1"); System.out.println(Thread.currentThread().getName()+" put 2"); queue.put("2"); System.out.println(Thread.currentThread().getName()+" put 3"); queue.put("3"); } catch (InterruptedException e) { e.printStackTrace(); } },"A").start(); new Thread(()->{ try { TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName()+" take 1"); queue.take(); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName()+" take 2"); queue.take(); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName()+" take 3"); queue.take(); } catch (InterruptedException e) { e.printStackTrace(); } },"B").start(); } }
消费者生产者模型
package com.prodconsumer; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 传统生产者消费者模式 题目要求 两种线程 一种线程执行加法 一种执行减法 轮番执行 + — + — + — 。。。执行5轮 * 思路分析 * 1. ReentrantLock 加锁 线程安全 * 2. while 判断 表示该线程什么时候干活 * 3.lock.newCondition();获取 condition 该干活时 condition.await(); 阻塞 * 4.干完活 condition.signalAll(); 通知唤醒其他线程 * @author liuxu * @date 2021/11/14 14:29 */ class Mydata{ Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); int num =0; public void increment() { lock.lock(); try{ // 判断 while(num!=0){ condition.await(); } //干活 num++; //通知唤醒 condition.signalAll(); System.out.println(Thread.currentThread().getName()+"\t"+num); }catch (Exception e){ }finally { lock.unlock(); } } public void dcrement() { lock.lock(); try{ // 判断 while(num==0){ condition.await(); } //干活 num--; //通知唤醒 condition.signalAll(); System.out.println(Thread.currentThread().getName()+"\t"+num); }catch (Exception e){ }finally { lock.unlock(); } } } public class ProConsumer { public static void main(String[] args) { Mydata mydata = new Mydata(); for (int i = 0; i < 5; i++) { new Thread(()->{ mydata.increment(); },"AA").start(); } for (int i = 0; i < 5; i++) { new Thread(()->{ mydata.dcrement(); },"BB").start(); } } }
面试题目:
Lock 和synchronized 的区别
1.原始构成
synchronized 是关键字 是jvm层面的锁,他的wait/notify依赖于monitor,对象只有在同步块或者方法中才能调用 wait/notify
Lock 是一个具体类 java.util.concurrent.locks.Lock; 是api层面的锁
2.使用方法
synchronized 不需要用户手动解锁, synchronized 代码块执行完毕 系统会让线程自动释放对该锁的占用
ReentrantLock 需要用户手动上锁解锁,有可能造成死锁,需要将 lock unlock配合try finally使用
3.是否可中断
synchronized 不可中断,除非抛出异常或者正常结束运行
ReentrantLock 可中断, (1)可以在tryLock方法设置超时方法
4.是否公平
synchronized 非公平
ReentrantLock 可选
5.锁绑定多个condition
synchronized 不支持,没有condition
ReentrantLock 支持
绑定多个condition展示
package com.prodconsumer; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @author liuxu * @date 2021/11/14 16:00 * * 三个线程AA BB CC * AA 打印5次 * BB 打印10次 * CC 打印3次 * 来 10轮 AA BB CC */ class MyContiondata{ Lock lock = new ReentrantLock(); //锁 private Condition condition1 = lock.newCondition();// 三个 condition private Condition condition2 = lock.newCondition(); private Condition condition3 = lock.newCondition(); int num =0; // 0 AA 1 BB 2 CC 控制条件 public void printAA(){ lock.lock(); try{ while (num!=0){ condition1.await();//AA 等待 } num=1; for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName()+"\t"+num+"i="+i); condition2.signal();//通知BB } }catch (Exception e){ }finally { lock.unlock(); } } public void printBB(){ lock.lock(); try{ while (num!=1){ condition2.await();//BB 等待 } for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"\t"+num+"i="+i); } num=2; condition3.signal();//通知CC }catch (Exception e){ }finally { lock.unlock(); } } public void printCC(){ lock.lock(); try{ while (num!=2){ condition3.await();//CC 等待 } for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName()+"\t"+num+"i="+i); } num=0; condition1.signal();//通知CC }catch (Exception e){ }finally { lock.unlock(); } } } public class Condtions { public static void main(String[] args) { MyContiondata contiondata = new MyContiondata(); new Thread(()->{ for (int i = 0; i < 10; i++) { contiondata.printAA(); } },"AA").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { contiondata.printBB(); } },"BB").start(); new Thread(()->{ for (int i = 0; i < 10; i++) { contiondata.printCC(); } },"CC").start(); } }
生产者消费者阻塞队列版
package com.prodconsumer; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** * @author liuxu * @date 2021/11/14 16:54 */ class MyQueueData{ private BlockingQueue blockingQueue = null; public volatile boolean flag =true; //是否开启生产 消费 AtomicInteger atomicInteger = new AtomicInteger(0); public MyQueueData(BlockingQueue blockingQueue) { this.blockingQueue = blockingQueue; } public void pro() throws InterruptedException { String s=null; while (flag){ s=atomicInteger.incrementAndGet() + ""; boolean offer = blockingQueue.offer(s, 2, TimeUnit.SECONDS); if(offer){ System.out.println(Thread.currentThread().getName()+"添加队列成功,data:"+s ); }else { System.out.println(Thread.currentThread().getName()+"2s内没有添加成功,data:"+s ); } TimeUnit.SECONDS.sleep(1); } System.out.println("main叫停,生产停止"); } public void consumer() throws InterruptedException { Object poll = null; while (flag){ poll= blockingQueue.poll(2, TimeUnit.SECONDS); if(poll!=null){ System.out.println(Thread.currentThread().getName()+"消费成功,poll:"+poll); }else { System.out.println(Thread.currentThread().getName()+"2s内没有得到数据,poll:"+poll); } TimeUnit.SECONDS.sleep(2); } System.out.println("main叫停,消费停止"); } } public class QueueProConsumer { public static void main(String[] args) throws InterruptedException { MyQueueData myQueueData = new MyQueueData(new ArrayBlockingQueue(10)); new Thread(()->{ try { myQueueData.pro(); } catch (InterruptedException e) { e.printStackTrace(); } },"pro").start(); new Thread(()->{ try { myQueueData.consumer(); } catch (InterruptedException e) { e.printStackTrace(); } },"consumer").start(); TimeUnit.SECONDS.sleep(100); myQueueData.flag=false; } }