JUC中的常见类

JUC ( java. util. concurrent )

一.Callable接口

Callable是一个接口.相当于把线程封装了一个"返回值".方便程序员借助多线程的方式计算结果.

代码示例:创建线程计算1+2+3+.......+ 1000,使用Callable.

  • 创建一个匿名内部类,实现Callable接口,Callable带有泛型参数,泛型参数表示返回值的类型.
  • 重写Callable的call方法,完成累加过程.直接通过返回值计算结果.
  • 把Callable实例使用FutureTask包装一下.
  • 创建线程,线程的构造方法传入FutureTask.此时新线程就会执行FutureTask内部的Callable的call方法,完成计算.计算结果就放到FutureTask对象中.
  • 在主线程中调用futureTask.get()能够阻塞等待新线程计算完毕.并获取到FutureTask中的结果.
   Callable<Integer> callable = new Callable<Integer>() {
            int sum = 0;
            @Override
            public Integer call() throws Exception {
                for (int i = 1; i <= 1000; i++) {
                   sum += i;
                }
                return sum;
            }
        };
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread t = new Thread(futureTask);
        t.start();
        int result = futureTask.get();
        System.out.println(result);

理解Callable

Callable和Runnable相对,都是描述一个"任务".而区别是,Callable描述的任务是带有返回值的,Runnable描述的是没有返回值的.

Callable通常需要搭配FutureTask来使用,FutureTask用来保存Callable的返回结果,因为,Callable往往是在另一个线程中执行的,啥时候执行完不确定.

FutureTask就可以负责这个等待结果出来的工作.

理解FutureTask

想象去吃麻辣烫.当点好餐后,后厨就开始做了.同时前台会给你一张"小票",这个小票就是FutureTask.后面我们可以随时凭借这张小票去查看自己的这份麻辣烫做出来了没.

二.ReentrantLock

可重入互斥锁.和synchronized定位类似,都是用来实现互斥的效果,保证线程安全.

ReentrantLock也是可重入锁."ReentrantLock"这个单词的原意就是"可重入"

ReentrantLock的用法:

  • lock() : 加锁,如果获取不到锁就死等.
  • trylock(超时时间) : 加锁,如果获取不到锁,等待一定时间后就放弃加锁.
  • unlock() : 解锁.
      ReentrantLock lock = new ReentrantLock();
        lock.lock();
        try {
            //代码
        }finally {
            lock.unlock();
        }

ReentrantLock 和 synchronized 的区别:

  • synchronized是一个关键字,是JVM内部实现的(大概率是c++).ReentrantLock是标准库的一个类,在JVM外实现的(基于Java实现).
  • synchronized使用时不需要手动释放锁.ReentrantLock使用时需要手动释放.使用来灵活,但是也容易遗漏unlock.
  • synchronized在申请锁时,会死等.ReetrantLock默认是非公平锁.可以通过构造方法传入一个true开启公平锁模式.

  • 更强大的唤醒机制.synchronized是通过Object的wait / notify 实现等待 - 唤醒.每次唤醒的是一个随即等待的线程.ReentrantLock搭配Condition类实现等待-唤醒.可以更精确控制唤醒某个指定的线程.

如何选择哪个锁呢:

  • 锁竞争不激烈的时候,使用synchronized,效率更高,自动释放更方便.
  • 锁竞争激烈的时候,使用ReentrantLock,搭配trylock更灵活控制加锁的行为,而不是死等.
  • 如果需要使用公平锁,使用synchronized.

三.信号量Semaphore

信号量,用来表示"可用资源的个数"本质上就是一个计数器.

理解信号量:

可以把信号量想象成时停车场的展示牌:当前车位100个.表示有100个可用资源.当有车开进去的时候,就相当于申请一个可用资源,可用车位就-1(这个称为信号量的P操作)当有车开出来的时候,就相当于释放一个可用资源,可用车位就+1(这个称为信号量的V操作)如果计数器的值已经为0了,还尝试申请资源,就会阻塞等待,直到有其他线程释放资源.

Semaphore的PV操作中的加减计数器操作都是原子的,可以在多线程环境下直接使用.

代码示例:

  Semaphore semaphore = new Semaphore(4);
        Runnable r = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("申请资源");
                    semaphore.acquire();
                    System.out.println("获取到了资源");
                    Thread.sleep(1000);
                    System.out.println("释放资源");
                    semaphore.release();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        };
        for (int i = 0; i < 20; i++) {
            Thread t = new Thread(r);
            t.start();
        }

四.CountDownLatch

同时等待N个任务执行结束.

好像跑步比赛,10个选手依次就位,哨声想才同时出发;所有选手都通过终点,才公布成绩.

  • 构造CountDownLatch实例,初始化10表示10个任务需要完成.
  • 每个任务执行完成,都调用latch.countDown().在CountDownLatch内部的计数器同时自减
  • 主线程中使用latch.await();阻塞等待所有任务执行完毕.相当于计数器为0了.
 CountDownLatch latch = new CountDownLatch(10);
        Runnable r = new Runnable() {
            @Override
            public void run() {
                try{
                    Thread.sleep((long) (Math.random()*10000));    
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        for (int i = 0; i < 10; i++) {
            new Thread(r).start();
        }
        //必须等到10人全部回来;
        latch.await();
        System.out.println("结束");

  • 14
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值