JUC 强大的辅助类

CountDownLatch

  1. CountDownLatch 主要有两个方法,当一个或多个线程调用 await 方法时,这些线程会阻塞。

  2. 其他线程调用 countDown 方法会将计数器减一(调用 countDown 方法的线程不会阻塞)。

  3. 当计数器的值变为 0 时,因 await 方法阻塞的线程会被唤醒,继续执行。

举个栗子:

package juc;

/**
 * @author : 雪飞oubai
 * @date : 2020/3/26 13:08
 * 例:6个同学陆续离开教室后 值班的班长才可以关门离开。
 */
public class CountDownLatchDemo {
    public static void main(String[] args) {
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName()+"离开了教室");
            },String.valueOf(i)).start();
        }
        System.out.println("main 班长关门走人");
    }
}

 这样的结果显然不是我们想要的,那么我们改怎么让进程按我们想的顺序执行呢?这就要用到 CountDownLatch

package juc;

import java.util.concurrent.CountDownLatch;

/**
 * @author : 雪飞oubai
 * @date : 2020/3/26 13:08
 */
public class CountDownLatchDemo {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(6);
        try {
            for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                countDownLatch.countDown();
                System.out.println(Thread.currentThread().getName()+"离开了教室");
            },String.valueOf(i)).start();
        }
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main 班长关门走人");
    }
}


CyclicBarrier

  1. 它的字面意思是可循环(Cyclic)使用的屏障(Barrier),用法像 集齐七颗龙珠可以许愿一样。

  2. 让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被拦截的线程才会继续干活。

  3. 线程进入屏障通过 CyclicBarrier 的 await 方法。

举个栗子:

package juc;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @author : 雪飞oubai
 * @date : 2020/3/26 14:14
 */
public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,() -> {
            System.out.println("七龙珠收集齐了,召唤神龙,你可以许愿了");
        });
        for (int i = 0; i < 7; i++) {
            new Thread(() -> {
                try {
                    System.out.println("拿到第"+Thread.currentThread().getName()+"颗龙珠");
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}

CountDownLatch 和 CyclicBarrier 区别:

  1. CountDownLatch 是一个计数器,线程完成一个记录一个,计数器递减,只能只用一次

  2. CyclicBarrier的计数器更像一个阀门,需要所有线程都到达,然后继续执行,计数器递增,提供 reset 功能,可以多次使用。


Semaphore

在信号量上我们可以定义两种操作:

  1. acquire(获取)当一个线程调用 acquire 操作时,它要么通过,成功回去信号量(信号量减一),要么一直等下去,直到有线程释放信号量,或超时。

  2. release(释放)实际上会将信号量的值加一,然后唤醒等待的线程。

  3. 信号量主要用于两个目的,一个用于多个共享资源的互斥访问,另一个用于并发线程数的控制。

举个例子:(抢车位)

package juc;

import java.util.concurrent.;
import java.util.concurrent.TimeUnit;

/**
 * @author : 雪飞oubai
 * @date : 2020/3/26 22:58
 */
public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3); // 模拟资源类
        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "\t抢到车位!");
                    TimeUnit.SECONDS.sleep(3);
                    // 暂停一会线程
                    System.out.println(Thread.currentThread().getName() + "\t离开了到车位!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release();
                }
            }, String.valueOf(i)).start();
        }
    }
}

 注意:

  //Semaphore semaphore = new Semaphore(3); // 模拟资源类
  // 若我们写成
 Semaphore semaphore = new Semaphore(1); // 模拟资源类
  //这个就相当于 在方法上加上 synchronized
  //若有要求:一个线程抢占资源后,停几秒钟,我们就可以这样。

猜你喜欢

转载自www.cnblogs.com/lililixuefei/p/13185961.html