java并发编程 第五期 阻塞队列

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;



    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值