Java并发工具类

833 阅读3分钟

1.CountDownLatch

CountDownLatch允许一个或者多个线程等待其他线程完成操作

比如这样一个需求:我们需要解析一个Excel里的多个sheet的数据,使用多线程每个线程分别解析一个sheet里的数据,等待所有的sheet解析完之后,程序提示解析完成,在这个需求中,要实现主线程等待所有线程完成sheet解析操作,最简单的是使用join方法

Join方法的作用:其实就是表示一旦某个线程调用了join方法,那么就要一直运行到该线程运行结束,才会运行其他进程

实现原理代码片段:

while(isAlive()){
    wait(0)
}

如果join线程存活则让线程永远等待下去,wait(0)表示线程永远等待下去

public class JoinCountDownLatchTest {
    public static void main(String[] args) throws InterruptedException {
        Thread parser1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("parser1 finish");
            }
        });
        Thread parser2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("parser2 finish");
            }
        });
        parser1.start();
        parser2.start();
        parser1.join();
        parser2.join();
        System.out.println("all parser finish");
    }
}

CountDownLatch也可以实现join的功能,并且比join的功能更多

  • countDownLatch的构造函数可以接收一个int类型的参数作为计数器

  • 计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了

  1. countDown():计数器的值减一

  2. await():等待计数器归零,然后再向下执行

import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest {
    static CountDownLatch c = new CountDownLatch(2);

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(1);
                c.countDown();
                System.out.println(2);
                c.countDown();
            }
        }).start();
        c.await();
        System.out.println(3);
    }
}

2.CycliBarrier

CycliBarrier这个单词的字面意思是可循环使用的屏障的。

它的功能是:让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被阻塞的线程才能执行下去。

  • 构造函数 CyclicBarrier(int parties) 屏障拦截的线程数量
  • await() 调用该方法时表示线程已经到达屏障,随即阻塞
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
    public static void main(String[] args) {
        CyclicBarrier c = new CyclicBarrier(7,()->{
            System.out.println("召唤神龙");
        });
        for (int i = 1; i <=7 ; i++) {
            int finalI = i;
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"收集"+finalI+"个龙珠");
                try {
                    c.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

以上两种的区别:

  • CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置

  • CountDownLatch相当于减法计数器,CyclicBarrier相当于加法计数器

3.Semaphore

Semaphore(信号量)是用来控制同时访问特定资源的线程数量

Semaphore 的构造方法需要传入一个参数,如 new Semaphore(10)

表示最多有10个线程可以获取到信号量,10个之后的线程再尝试获取时就会被阻塞。

获取信号量使用:s.acquire()方法;

释放信号量使用:s.release()方法。

只有前边的线程释放掉后,后面的线程(10个之后)才能被唤醒,重新获取信号量

假设有三个车位,此时有六辆车需要停车:

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

public class SemaphoreTest {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);

        for(int i=1;i<=6;i++){
            new Thread(()->{
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"抢到车位");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread().getName()+"离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release();
                }
            }).start();
        }
    }
}