# JDK 中Concurrent包的基础知识

JDK 中Concurrent包的基础知识


阻塞队列BlockingQueue

BlockingQueue通过建立线程安全的队列,从而快速方便的设计高质量的多线程程序。BlockingQueue通常应用在消费者生产者场景。举个例子:一个电动汽车,只要有电,他就能运动。

BlockingQueue接口的具体实现

在这里插入图片描述

BlockingQueue生产者消费者实例
  • Producer
public class Producer implements Runnable {

    private static Logger logger= LoggerFactory.getLogger(Producer.class);

    // 线程是否在运行
    public static boolean isRunning=true;
    // 阻塞队列
    private BlockingQueue blockingQueue=null;
    // 随机数的最大范围值
    private static final int DEFAULT_RANGE_FOR_SLEEP = 1000;
    // 随机数对象
    private Random random=new Random();

    public Producer(BlockingQueue blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        logger.info("生产者线程启动!......");
        logger.info("生产者线程id为==========="+Thread.currentThread().getId()+"===========");
        long id = Thread.currentThread().getId();
        try{
            while(isRunning){
                int num = random.nextInt(DEFAULT_RANGE_FOR_SLEEP);
                System.out.println("生产者放入阻塞队列中的数据为======"+num);
                blockingQueue.put(num);
                Thread.sleep(3000);
            }
        }catch (Exception e){
            e.printStackTrace();
            logger.error(e.getMessage());
        }finally {
            logger.info("生产者线程"+id+"正在中止!");
            Thread.currentThread().interrupt();
            logger.info("生产者线程结束!......");
        }
    }
}
  • Consumer
public class Consumer implements Runnable {

    private Logger logger= LoggerFactory.getLogger(Consumer.class);

    protected BlockingQueue queue=null;
    private static boolean isRunning=true;

    public Consumer(BlockingQueue queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try{
            logger.info("消费者线程启动......");
            logger.info("消费者线程id为======="+Thread.currentThread().getId()+"==========");
            while(isRunning){
                Object take = queue.take();
                String s = String.valueOf(take);
                if(s.endsWith("4") || s.endsWith("3")){
                    System.out.println("找到想要的东西了生产者结束生产!..........");
                    Producer.isRunning=false;
                    isRunning=false;
                }
                if(s==null || s.equals(" ")){
                    logger.info("--------生产者队列空了------------");
                }else {
                    System.out.println("消费者消费的数据为:" + queue.take());
                }
            }
        }catch (Exception e){
            logger.error(e.getMessage());
        }finally {
            logger.info("消费者线程"+Thread.currentThread().getId()+"正在中止!");
            logger.info("消费者消费结束!......");
        }
    }
}
  • BlockingQequeTest
public class BlockingQequeTest {

    private static Logger logger= LoggerFactory.getLogger(BlockingQequeTest.class);

    public static void main(String[] args) {
        // 申明一个容量为10的缓存队列
        BlockingQueue blockingQueue=new ArrayBlockingQueue(10);
        logger.info("阻塞队列测试开始!......");

        Producer producer=new Producer(blockingQueue);
        Consumer consumer=new Consumer(blockingQueue);

        new Thread(producer).start();
        new Thread(consumer).start();

        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
        }
    }
}
BlockingQeque接口中的方法
// 给定元素放到指定的队列中
BlockingQueue.add(java.lang.Object)
BlockingQueue.remove(java.lang.Object)
BlockingQueue.put(java.lang.Object) throws java.lang.InterruptedException
BlockingQueue.contains(java.lang.Object)
BlockingQueue.poll(long,java.util.
BlockingQueue.offer(java.lang.Object,long,java.util.
BlockingQueue.offer(java.lang.Object)
BlockingQueue.drainTo(java.util.Collection)
BlockingQueue.drainTo(java.util.Collection,int)
// 获取队列中剩余的空间                    
BlockingQueue.remainingCapacity()
// 从队列中获取值,如果队列中没有值,线程会一直阻塞
BlockingQueue.take() throws java.lang.InterruptedException

DelayQueue 延时队列

DelayQueue是一个BlockingQueue无界阻塞队列,要实现DelayQueue延时队列要实现Delayed接口,队列元素需要实现getDelay(TimeUnit unit)方法和compareTo(Delayed o)方法, getDelay定义了剩余到期时间,compareTo方法定义了元素排序规则。

DelayQueue延时队列实例
  • Order类
public class Order implements Delayed {

    @JsonFormat(pattern="yyyy-MM-dd",timezone = "GMT+8")
    private long time;
     String name;

    public Order(long time, String name,TimeUnit unit) {
        this.time = System.currentTimeMillis() + (time > 0? unit.toMillis(time): 0);
        this.name = name;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return time-System.currentTimeMillis();
    }

    @Override
    public int compareTo(Delayed o) {
        Order order= (Order) o;
        long l = this.time - order.time;
        if(l<=0){
            return -1;
        }else {
            return 1;
        }
    }

    @Override
    public String toString() {
        return "Order{" +
                "time=" + time +
                ", name='" + name + '\'' +
                '}';
    }
}
  • DelayQueueTest
public class DelayQueueTest {

    public static void main(String[] args) {
        Order order=new Order(5,"order1", TimeUnit.SECONDS);
        Order order1=new Order(10,"order2", TimeUnit.SECONDS);
        Order order2=new Order(15,"order3", TimeUnit.SECONDS);
        DelayQueue<Order> delayQueue=new DelayQueue<>();
        delayQueue.put(order1);
        delayQueue.put(order2);
        delayQueue.put(order);
        System.out.println("开始时间:"+ TimeUtils.getCurrentDateTime());
        for (int i = 0; i < 3; i++) {
            Order order3 = null;
            try {
                order3 = delayQueue.take();
                System.out.format("name:{%s}, time:{%s}\n",order3.name, TimeUtils.getCurrentDateTime());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

ExecutorService 执行器服务

interface ExecutorService表示一个异步执行机制,是我们能够在后台执行任务,ExecutorService的实现就是一个线程池的实现。

Demo
@Test
public void test1(){
    // 使用NewFixedThreadPool创建一个ExecutorService,将一个Runnable接口的是实现立类传给execute()方法,
    // ExecutorService中的某个线程会执行该Runnable
    ExecutorService executorService= Executors.newFixedThreadPool(10);
    executorService.execute(()->{
        System.out.println("当前线程Id为"+Thread.currentThread().getId());
    }
                           );
    executorService.shutdown();
}

CountDownLatch

CountDownLatch是一个计数的锁,通过countDown()方法将此计数值减为0同时唤起之前await()调用的线程,一般用于某些任务执行完成后再执行其他任务的场景中。

Demo
public class CountDownLatchTest {

    private static Logger logger= LoggerFactory.getLogger(CountDownLatch.class);

    /**
     * 场景描述:有一个主线程正在跑,当主线程完成后其他的线程才能开始工作,当其他线程都结束后主线程才能结束
     */
    @Test
    public void test() throws InterruptedException {
        CountDownLatch startFlag=new CountDownLatch(1);
        CountDownLatch other=new CountDownLatch(5);

        // 创建并且启动5个线程
        for (int i = 0; i < 5; i++) {
            new Thread(()->{
                try {
                    Thread.sleep(4000);
                    // 等待主线程发出开始的信号
                    startFlag.await();
                    System.out.println("其他线程"+Thread.currentThread().getId()+"正在执行...........");
                    // 其他线程执行完成,释放一个完成信号
                    other.countDown();
                    logger.info("其他线程执行结束...........");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        logger.info("主线程正在执行!..........");
        logger.info("主线程执行结束,其他线程开始执行!..........");
        // 主线程执行完成,发出开始信号,其他线程开始执行
        startFlag.countDown();
        System.out.println("主线程已经执行完成正在等待其他线程执行结束");
        other.await();
    }
}

线程池执行者ThreadPoolExecutor

ThreadPoolExecutorExecutorService接口的一个实现,ThreadPoolExecutor包含的线程池能够包含不同数量的线程,池中线程的数量由核心线程大小和最大线程数量决定。

ThreadPoolExecutor构造函数
@Test
public void test1(){
    int corePoolSize=5;
    int maxPoolSize=10;
    long keepAliveTime=500;

    LinkedBlockingQueue linkedBlockingQueue=new LinkedBlockingQueue();
    for (int i = 0; i < 3; i++) {
        linkedBlockingQueue.add(new Thread(()->{
            System.out.println("当前线程的Id为"+Thread.currentThread().getId());
        }));
    }

    ExecutorService executorService= (ExecutorService) new ThreadPoolExecutor(corePoolSize,
                                                                              maxPoolSize,
                                                                              keepAliveTime,
                                                                              TimeUnit.MILLISECONDS,
                                                                              linkedBlockingQueue);

    List<Runnable> runnables = executorService.shutdownNow();
    runnables.stream().forEach(x->{
        System.out.println(x);
    });
    executorService.shutdown();
}

Lock锁

如果一段代码被Synchronized修饰了。当一个线程获取了对应的锁,并执行该代码块时,其他线程只能一直等待,等待获取锁的线程释放锁,才去执行别的代码。Synchronized代码块不能保证进入访问等待线程的先后顺序。Synchroized块必须完整地包含在单个方法里,Lock对象可以把它的Lock()unLock()方法的调用放在不同的方法里面。

接口包含的方法
lock()
lockInterruptibly() throws java.lang.InterruptedException
newCondition()
tryLock()
tryLock(long,java.util.concurrent.TimeUnit) throws java.lang.InterruptedException
unlock()
Lock中锁的使用方法
  • Lock()方法是平常使用最多的一个方法,用来获取锁,如果锁已经被占用则进行等待。采用Lock,必须主动去释放锁,在发生异常的时候不会释放锁,在Finallly后进行释放锁的操作。
Lock lock=....;
lock.lock();
try{
    // 处理任务
}catch(Exception e){
    
}finally{
    // finally中释放锁
    lock.unlock();
}
  • tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功则返回true;如果获取失败(锁已经被其他线程占用)则返回false。当拿不到锁的时候会一直等待。
Lock lock=....;
if(lock.tryLock()){
    try{
        // 处理任务
    }catch(Exception e){
        
    }finally(){
        // 释放锁
        lock.unlock();
    }
}else{
    // 如果拿不到锁,则进行其他操作
}
  • 使用Lock锁
@Test
public void test1(){
    Lock lock=new ReentrantLock();
    for (int i = 0; i < 5; i++) {
        int finalI = i;
        lock.lock();
        try {
            new Thread(() -> {
                Thread.currentThread().setName("线程" + finalI);
                System.out.println("当前的线程为"+Thread.currentThread().getId()+"线程名称为:"+Thread.currentThread().getName());
            }).start();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    try {
        Thread.sleep(6000);
        System.out.println("主线程信息为:"+Thread.currentThread().getId()+"============================");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

CountDownLatch使用

使用场景:主线程在等子线程全部执行完成、释放资源后再执行主线程的任务

  • 例子
@RestController
@RequestMapping("/thread")
public class ThreadPoolTestController {

    public static final Logger logger = LoggerFactory.getLogger(ThreadPoolTestController.class);

    /**
     * 线程池的基本大小
     */
    final static int CORE_POOL_SIZE = 10;
    /**
     * 线程池允许的最大线程数
     */
    static int MAX_POOL_SIZE = 20;


    @RequestMapping("/test1")
    public void test1() {
        logger.info("=====>CountDawnlanch测试开始...");
        ExecutorService executorService = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, 5, TimeUnit.MINUTES, new ArrayBlockingQueue<>(100));
        int num = 10000;
        CountDownLatch countDownLatch = new CountDownLatch(num);
        for (int i = 0; i < num; i++) {
            int finalI = i;
            try {
                executorService.execute(() -> {
                    try {
                        for (int j = 0; j < finalI; j++) {
                            logger.info("=====>线程" + finalI + "正在处理第" + j + "个任务");
                        }
                        logger.info("=====>子线程的ID========================={}", Thread.currentThread().getId());
                    } catch (Exception e) {
                        logger.info("=====>发生错误", e.getMessage(), e);
                    } finally {
                        countDownLatch.countDown();
                        logger.info("=====>当前countDownLatch的数为:" + countDownLatch.getCount());
                    }
                });
            }catch (Exception e){
                logger.error("=====>线程中出现错误",e);
                countDownLatch.countDown();
            }
        }
        try {
            countDownLatch.await();
            logger.info("=====>子线程中的任务执行完成");
            logger.info("=====================>主线程的信息为================{}", Thread.currentThread().getId());
        } catch (InterruptedException interruptedException) {
            logger.info("=====>countDownLatch出错", interruptedException);
        }
    }
}

。。。。卧槽看的吐了,搞不下去了有时间再看吧。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值