【Java多线程】总结(完)JUC下常用类

JUC下常用类

java.util.concurrent 下的类就叫 JUC 类,JUC 下典型的类有:

ReentrantLock :可重入锁;
Semaphore :信号量;
CountDownLatch :计数器;
CyclicBarrier :循环屏障

1 可重入互斥锁ReentrantLock:

1 类似 synchronized
2 ReentrantLock 的用法:

lock(): 加锁, 如果获取不到锁就一直等;
trylock(超时时间): 加锁, 如果获取不到锁, 等待一定的时间之后就放弃加锁;
unlock(): 解锁。

3 ReentrantLock 和 synchronized 的区别:

  1. synchronized 是关键字 ,JVM 内部实现的(基于 C++实现).ReentrantLock 是标准库的一个类, 在 JVM 外实现的(基于 Java 实现).
  2. synchronized 使用时不需要手动释放锁. ReentrantLock 使用时需要手动释放. 使用起来更灵活,但是也容易遗漏 unlock
  3. synchronized 在申请锁失败时, 会死等. ReentrantLock 可以通过 trylock 的方式等待一段时间就放弃.
  4. synchronized 是非公平锁, ReentrantLock 默认是非公平锁. 可以通过构造方法传入一个 true 开启公平锁模式.
  5. 更强大的唤醒机制. synchronized 是通过 Object 的 wait / notify 实现等待-唤醒. 每次唤醒的是一个随机等待的线程. ReentrantLock 搭配 Condition 类实现等待-唤醒, 可以更精确控制唤醒某个指定的线程.
2 信号量Semaphore:可以实现限流

用来表示 “可用资源的个数”,本质上就是一个计数器。该类用于控制信号量的个数,构造时传入个数。总数就是控制并发的数量。假如是5,程序执行前用acquire()方法获得信号,则可用信号变为4,程序执行完通过release()方法归还信号量,可用信号又变为5。如果可用信号为0,acquire就会造成阻塞,等待release释放信号。acquire和release方法可以不在同一个线程使用

  1. acquire:获取令牌
  2. release:发布令牌

public class SemaphoreDemo {
    // 创建信号量
    static Semaphore semaphore = new Semaphore(2);
 
    public static void main(String[] args) {
        // 创建固定线程数的线程池
        ExecutorService service = Executors.newFixedThreadPool(5);
 
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100 * i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            service.submit(() -> {
                Thread currThread = Thread.currentThread();
                System.out.println("进入线程:" + currThread.getName());
                try {
                    // 获取令牌
                    semaphore.acquire();
                    System.out.println(currThread.getName() + "得到令牌:" + LocalDateTime.now());
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println(currThread.getName() + "释放令牌:" + LocalDateTime.now());
                    semaphore.release();
                }
            });
        }
        service.shutdown();
    }
}

信号量个数为2,线程1和线程2先得到令牌,信号量为0,直到线程1释放了令牌,线程3才可以得到令牌,线程2释放了令牌,线程4才能拿到令牌
信号量个数为2,线程1和线程2先得到令牌,信号量为0,直到线程1释放了令牌,线程3才可以得到令牌,

3 CountDownLatch:计数器:

判断线程池任务是否已经全部执行完

  1. countDown:计数器减一
  2. await:阻塞等待所有的任务执行完(等待CountDownLatch==0 继续之后的代码
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        // 创建计算器
        CountDownLatch countDownLatch = new CountDownLatch(5);
        // 创建线程池
        ExecutorService service = Executors.newFixedThreadPool(5);
        // 创建新线程执行任务
        for (int i = 1; i <= 5; i++) {
            service.submit(() -> {
                Thread currThread = Thread.currentThread();
                System.out.println(currThread.getName() + "开始起跑");
                int runTime = new Random().nextInt(5) + 1;
                try {
                    TimeUnit.SECONDS.sleep(runTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(currThread.getName() + "到达终点,用时:" + runTime);
                countDownLatch.countDown();
            });
        }

        countDownLatch.await();
        System.out.println("比赛结果宣布!");
    }
}

在这里插入图片描述

4 CyclicBarrier 循环栅栏:线程分组的阻塞

它可以协同多个线程,让多个线程在这个屏障前等到,直到所有线程都到达了这个屏障时,再一起执行后面的操作。假如每个线程各有一个await,任何一个线程运行到await方法时就阻塞,直到最后一个线程运行到await时才同时返回。

  1. await:计数器减一,判断当前计数器是否为0,如果为0,冲破栅栏执行之后的代码,否则阻塞等待,直到冲破栅栏
public class CyclicBarrierDemo {
    public static void main(String[] args) {
        //循环屏障
        CyclicBarrier cyclicBarrier=new CyclicBarrier(5, new Runnable() {
            @Override
            public void run() {
                System.out.println("冲破循环屏障,计数器为0");
            }
        });
        ExecutorService service= Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            int finalI=i;
            service.submit(()->{
               Thread currThread=Thread.currentThread();
                System.out.println("执行线程"+currThread.getName());
                try {
                    Thread.sleep(500*finalI);
                    cyclicBarrier.await();//执行阻塞等待(计数器减一 直到循环屏障计数为0时 执行后面代码
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println("线程执行完成:" + currThread.getName());
            });
        }
    }
}

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值