JAVA并发工具类

JAVA中并发工具类CountDownLatch、CyclicBarrier和Semaphore的概念和使用。

一、CountDownLatch(计数器)

  CountDownLatch的应用场景是某个线程任务需要等待其他的线程全部执行完毕才能执行,这时候就可以使用CountDownLatch类。其内部使用计数器实现,计数器的初始值为线程的数量,可以在构造对象时传入。之后每个线程调用其countDown()方法,计数器的值就会减一。而当计数器初始值到达0时,表示所有的线程已经完成了任务。因此之前因为调用await()方法而等待的线程就可以恢复执行任务。

import java.util.concurrent.CountDownLatch;
public class Main {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch cdl = new CountDownLatch(2);
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + ", begin...");
            cdl.countDown();
            System.out.println(Thread.currentThread().getName() + ", end...");
        }).start();
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + ", begin...");
            cdl.countDown();
            System.out.println(Thread.currentThread().getName() + ", end...");
        }).start();
        //只有调用了两次countDown方法,计数器值才变为0。此时当前线程才被唤醒继续执行
        cdl.await();
        System.out.println("两个Thread执行完毕.....");
        System.out.println("主线程继续执行");
        for (int i = 0; i < 10; i ++) {
            System.out.println(Thread.currentThread().getName() + ", i:" + i);
        }
    }

}

二、CyclicBarrier(屏障)

  CyclicBarrier初始化时同样也规定一个数目,然后计算调用其await()而进入等待的线程数。CyclicBarrier可看成是个障碍,所有的线程调用await()方法就被阻塞且线程数量加1,当被阻塞的线程数量达到规定的数目。说明指定数量的线程均匀执行到调用await()的位置,此时再全部放行往下执行。即所有线程必须到齐才能一起通过这个障碍。另外CyclicBarrier初始时还可带一个Runnable的参数,此Runnable任务在CyclicBarrier的数目到达后,所有其他线程被唤醒前执行。

import java.util.concurrent.CyclicBarrier;
public class Main {

    public static void main(String[] args) {
        CyclicBarrier cbr = new CyclicBarrier(5);
        for (int i = 0; i < 5; i ++) {
            Writer writer = new Writer(cbr);
            writer.start();
        }
    }

}

class Writer extends Thread {

    private CyclicBarrier cbr;

    public Writer(CyclicBarrier cbr) {
        this.cbr = cbr;
    }

    @Override
    public void run() {
        try {
            System.out.println("线程" + Thread.currentThread().getName() + "正在写入数据");
            Thread.sleep(3000);
            System.out.println("线程" + Thread.currentThread().getName() + "写入成功");
            //这里只有5个线程都调用await方法,才会往下执行,因此相当于屏障
            cbr.await();
            System.out.println("所有线程执行完毕");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

三、Semaphore(计数信号量)

  Semaphore是一种基于计数的信号量,它可以设定一个阈值,基于此,多个线程竞争获取许可信号,做自己的申请后归还,超过阈值后,线程申请许可信号将会被阻塞。因此Semaphore可以用来构建一些对象池、资源池之类的,比如数据库连接池。也可以创建计数为1的Semaphore实现互斥锁的机制,也叫做二元信号量。使用Semaphore类时,其availablePermits()方法可以获取当前可用的资源数量。acquire()申请信号量资源,无资源可用时会阻塞当前线程、release()释放当前获取的资源。其中acquire()和release()默认都是参数为1,也可传入int参数申请指定数量的资源。

import java.util.concurrent.Semaphore;
public class Main {

    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(4);
        for (int i = 1; i <= 10; i ++) {
            UserThread userThread = new UserThread("用户" + i + "号", semaphore);
            userThread.start();
        }
    }

}

class UserThread extends Thread {

    private String name;
    private Semaphore jsShop;

    public UserThread(String name, Semaphore jsShop) {
        this.name = name;
        this.jsShop = jsShop;
    }

    @Override
    public void run() {
        try {
            jsShop.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + "得到服务");
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(name + "服务结束");
        jsShop.release();
    }
}
posted @ 2024-07-02 23:41  Idempotent  阅读(1)  评论(0编辑  收藏  举报