Several synchronization auxiliary classes of JAVA

Java provides us with some 同步辅助类of these auxiliary classes, we can flexibly grasp the state of the thread in multi-threaded programming.

CountDownLatch

CountDownLatchOne 同步辅助类, which allows one or more threads to wait until a set of operations that are being performed in other threads are completed.

Two more critical methods in CountDownLatch:

public void await() throws InterruptedException;
public void countDown();

CountDownLatchIt is 计数器a value that needs to be set in its construction method to set the number of counts. After each countDown()method call, this counter is decremented 1, and CountDownLatch blocks await()the thread calling the method until 计数器the value of CountDownLatch becomes 0.

Imagine that there is such a function that requires Thread1, Thread2, Thread3, and Thread4 to count the sizes of the four disks C, D, E, and F respectively. All threads are counted and handed over to the main thread for summary. It is very easy to use CountDownLatch to complete it. .

public class CountDownLatchTest {

    private static CountDownLatch count = new CountDownLatch(4);
    private static ExecutorService service = Executors.newFixedThreadPool(6);

    public static void main(String args[]) throws InterruptedException {

        for (int i = 0; i < 4; i++) {
            service.execute(() -> {
                // 模拟任务耗时
                try {
                    int timer = new Random().nextInt(5);
                    TimeUnit.SECONDS.sleep(timer);
                    System.out.printf("%s时完成磁盘的统计任务,耗费%d秒.\n", new Date().toString(), timer);
                    // 任务完成之后,计数器减一
                    count.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        // 主线程一直被阻塞,知道count的计数器被设置为0
        count.await();

        System.out.printf("%s时全部任务都完成,执行合并计算.\n", new Date().toString());
        service.shutdown();
    }
}

CyclicBarrier

BarrierIt means barrier in English. This synchronization tool blocks the calling thread until the condition is met, and the blocked thread is opened at the same time.

public int await() throws InterruptedException, BrokenBarrierException

CyclicBarrierWhen initializing, set a barrier number. When a thread calls a await()method, the thread will be blocked. When await()the number of threads called reaches the barrier number, the main thread will cancel the state of all blocked threads.

In CyclicBarrierthe constructor of , you can also set one barrierAction.

After all the barriers are reached, a thread is started to run the code inside. Here is an example: Athletes in the 100-meter race need to prepare before starting, and only after all the runners are ready can they start at the same time.

public class CyclicBarrierTest {

    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(8);
    private static ExecutorService service = Executors.newFixedThreadPool(50);

    public static void main(String args[]) {
        for (int i = 1; i < 9; i++) {
            service.execute(new Thread(new Runner(i, cyclicBarrier)));
        }
        service.shutdown();
    }
}
// 运动员类
public class Runner implements Runnable {

    private int number;
    private CyclicBarrier cyclicBarrier;

    public Runner(int number, CyclicBarrier cyclicBarrier) {
        this.number = number;
        this.cyclicBarrier = cyclicBarrier;
    }

    @Override
    public void run() {
        try {
            int timer = new Random().nextInt(5);
            TimeUnit.SECONDS.sleep(timer);
            System.out.printf("%d号选手准备完毕,准备时间%d\n", number, timer);
            cyclicBarrier.await();
            System.out.printf("%d号选手于%s时起跑!\n", number, new Date().toString());
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}

output:

1号选手准备完毕,准备时间0
4号选手准备完毕,准备时间0
5号选手准备完毕,准备时间1
8号选手准备完毕,准备时间1
3号选手准备完毕,准备时间2
2号选手准备完毕,准备时间3
7号选手准备完毕,准备时间3
6号选手准备完毕,准备时间3
7号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
2号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
5号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
6号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
3号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
8号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
4号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
1号选手于Sun Mar 27 21:19:00 CST 2016时起跑!

相比CountDownLatchCyclicBarrier是可以被循环使用的,而且遇到线程中断等情况时,还可以利用reset()方法,重置计数器,从这些方面来说,CyclicBarrier会比CountDownLatch更加灵活一些。

Semaphore

Semaphore被用于控制特定资源在同一个时间被访问的个数。类似连接池的概念,保证资源可以被合理的使用。

Semaphore的几个重要方法:

// 获取资源
public void acquire() throws InterruptedException
// 释放资源
public void release()

Semaphore的构造方法可以设置一个int值来设置一个计数器,用于表示资源同时可以被多少外部环境使用。每使用一次acquire(),计数器都会去减去一,而每次调用release()计数器则会增加一。当计数器的值为0的时候,外部的环境被阻塞,直到Semaphore有空闲的资源可以被使用。

public class SemaphoreTest {

    private static Semaphore semaphore = new Semaphore(3);
    private static ExecutorService service = Executors.newFixedThreadPool(6);

    public static void main(String args[]) {

        // 执行9个任务
        for (int i = 0; i < 9; i++) {
            service.execute(() -> {
                try {
                    semaphore.acquire();
                    System.out.printf("%s时获取资源,并调用.\n", new Date().toString());
                    // 线程挂起3秒
                    TimeUnit.SECONDS.sleep(3);
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        service.shutdown();
    }
}

运行的结果就是:

Sun Mar 27 20:18:16 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:16 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:16 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:19 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:19 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:19 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:22 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:22 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:22 CST 2016时获取资源,并调用.

虽然线程池允许6个最大线程数量,但是同一个时间内只用三个任务被执行。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325810126&siteId=291194637