Java and contract Advanced synchronization tool

Java and contract Advanced synchronization tool

In Java and contract refers to the java.util.concurrent classes and interfaces (referred to the JUC) package and other subpackages, which provides various functions to support concurrent Java, such as:

  • It provides a thread pool to create a class of ThreadPoolExecutor, Executors and so on;
  • Providing a variety of locks, such as Lock, ReentrantLock the like;
  • Providing a variety of thread-safe data structure, such as ConcurrentHashMap, LinkedBlockingQueue, DelayQueue the like;
  • It provides more advanced thread synchronization structures, such as CountDownLatch, CyclicBarrier, Semaphore and so on.

In the previous section we have introduced the use of the thread pool, thread-safe data structure in detail, this article we will focus on learning about Java and contracting more advanced thread synchronization class: CountDownLatch, CyclicBarrier, Semaphore and Phaser and so on.

CountDownLatch introduction and use of

CountDownLatch (lockout) it can only be seen as a subtraction counter that allows one or more threads waiting to execute.
CountDownLatch There are two important ways:

  • countDown (): the counter is decremented by 1;
  • await (): when the counter is not zero, then the calling thread to block this method, one or all of the thread when the counter is 0, waiting to wake up.

CountDownLatch usage scenarios:
with life scenarios, for example, like to go to hospital for medical examination, usually people will line up early to go to the hospital, but only until doctors start work before the official start of the physical examination, the doctor must complete a medical examination to all people in order to work, this the case is necessary to use CountDownLatch, process-: patients line up doctors to work → → → complete physical examination the doctor after work.

CountDownLatch following sample code:

// 医院闭锁
CountDownLatch hospitalLatch = new CountDownLatch(1);
// 患者闭锁
CountDownLatch patientLatch = new CountDownLatch(5);
System.out.println("患者排队");
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
    final int j = i;
    executorService.execute(() -> {
        try {
            hospitalLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("体检:" + j);
        patientLatch.countDown();
    });
}
System.out.println("医生上班");
hospitalLatch.countDown();
patientLatch.await();
System.out.println("医生下班");
executorService.shutdown();

The above program execution results are as follows:

Patients queue

Doctors work

Physical examination: 4

Physical examination: 0

Physical examination: 1

Physical examination: 3

Physical examination: 2

Doctors from work

FIG execution process is as follows:

CyclicBarrier introduction and use of

CyclicBarrier (circulation barrier) which can be achieved so that a group of threads while waiting for execution after certain conditions are met.

CyclicBarrier use the classic scenario is the bus departure, we are here in order to simplify understanding of the definition, as long as each bus full of four people on the grid, behind the people will line up in order to follow the appropriate standards.

Its constructor method CyclicBarrier(int parties,Runnable barrierAction)which, parties expressed several threads waiting to participate, barrierAction representation after triggering conditions are met. CyclicBarrier use the await () method to identify the current thread has reached the barrier point, then blocked.

CyclicBarrier following sample code:

import java.util.concurrent.*;
public class CyclicBarrierTest {
    public static void main(String[] args) throws InterruptedException {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(4, new Runnable() {
            @Override
            public void run() {
                System.out.println("发车了");
            }
        });
        for (int i = 0; i < 4; i++) {
            new Thread(new CyclicWorker(cyclicBarrier)).start();
        }
    }
    static class CyclicWorker implements Runnable {
        private CyclicBarrier cyclicBarrier;
        CyclicWorker(CyclicBarrier cyclicBarrier) {
            this.cyclicBarrier = cyclicBarrier;
        }
        @Override
        public void run() {
            for (int i = 0; i < 2; i++) {
                System.out.println("乘客:" + i);
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

The above program execution results are as follows:

Passenger: 0

Passenger: 0

Passenger: 0

Passenger: 0

Start the

Passenger: 1

Passenger: 1

Passenger: 1

Passenger: 1

Start the

FIG execution process is as follows:

Semaphore introduction and use of

Semaphore (Semaphore) used to access and manage the use of multiple threads of control resources. Semaphore is like guard the parking lot, parking spaces can control the use of resources. For example, to the 5 car, only two parking spaces, the guard can first put into two cars, and other vehicles out there after, let into the back of the car.

Semaphore following sample code:

Semaphore semaphore = new Semaphore(2);
ThreadPoolExecutor semaphoreThread = new ThreadPoolExecutor(10, 50, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
for (int i = 0; i < 5; i++) {
    semaphoreThread.execute(() -> {
        try {
            // 堵塞获取许可
            semaphore.acquire();
            System.out.println("Thread:" + Thread.currentThread().getName() + " 时间:" + LocalDateTime.now());
            TimeUnit.SECONDS.sleep(2);
            // 释放许可
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

The above program execution results are as follows:

Thread: pool-1-thread-1 Time: 2019-07-10 21:18:42

Thread: pool-1-thread-2 Time: 2019-07-10 21:18:42

Thread: pool-1-thread-3 Time: 2019-07-10 21:18:44

Thread: pool-1-thread-4 Time: 2019-07-10 21:18:44

Thread: pool-1-thread-5 Time: 2019-07-10 21:18:46

FIG execution process is as follows:

Phaser (phase shifter) JDK 7 is provided, its function is to wait for all threads after arrival, only to continue or to start a new set of tasks.

After such a tour, we require that all members must have arrived at the designated place after, in order to start a go attractions, after reaching attractions can each play, after all must reach the designated place, in order to continue to go down a spot start, similar to scene is very suitable for use Phaser.

Phaser following sample code:

public class Lesson5\_6 {
    public static void main(String[] args) throws InterruptedException {
        Phaser phaser = new MyPhaser();
        PhaserWorker[] phaserWorkers = new PhaserWorker[5];
        for (int i = 0; i < phaserWorkers.length; i++) {
            phaserWorkers[i] = new PhaserWorker(phaser);
            // 注册 Phaser 等待的线程数,执行一次等待线程数 +1
            phaser.register();
        }
        for (int i = 0; i < phaserWorkers.length; i++) {
            // 执行任务
            new Thread(new PhaserWorker(phaser)).start();
        }
    }
    static class PhaserWorker implements Runnable {
        private final Phaser phaser;
        public PhaserWorker(Phaser phaser) {
            this.phaser = phaser;
        }
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " | 到达" );
            phaser.arriveAndAwaitAdvance(); // 集合完毕发车
            try {
                Thread.sleep(new Random().nextInt(5) * 1000);
                System.out.println(Thread.currentThread().getName() + " | 到达" );
                phaser.arriveAndAwaitAdvance(); // 景点 1 集合完毕发车
                Thread.sleep(new Random().nextInt(5) * 1000);
                System.out.println(Thread.currentThread().getName() + " | 到达" );
                phaser.arriveAndAwaitAdvance(); // 景点 2 集合完毕发车
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    // Phaser 每个阶段完成之后的事件通知
    static class MyPhaser extends Phaser{
        @Override
        protected boolean onAdvance(int phase, int registeredParties) { // 每个阶段执行完之后的回调
            switch (phase) {
                case 0:
                    System.out.println("==== 集合完毕发车 ====");
                    return false;
                case 1:
                    System.out.println("==== 景点1集合完毕,发车去下一个景点 ====");
                    return false;
                case 2:
                    System.out.println("==== 景点2集合完毕,发车回家 ====");
                    return false;
                default:
                    return true;
            }
        }
    }
}

The above program execution results are as follows:

Thread-0 | arrive

Thread-4 | 到达

Thread-3 | 到达

Thread-1 | 到达

Thread-2 | 到达

==== 集合完毕发车 ====

Thread-0 | 到达

Thread-4 | 到达

Thread-1 | 到达

Thread-3 | 到达

Thread-2 | 到达

==== 景点1集合完毕,发车去下一个景点 ====

Thread-4 | 到达

Thread-3 | 到达

Thread-2 | 到达

Thread-1 | 到达

Thread-0 | 到达

==== 景点2集合完毕,发车回家 ====

相关面试题

1.以下哪个类用于控制某组资源的访问权限?

A:Phaser
B:Semaphore
C:CountDownLatch
D:CyclicBarrier

答:B

2.以下哪个类不能被重用?

A:Phaser
B:Semaphore
C:CountDownLatch
D:CyclicBarrier

答:C

3.以下哪个方法不属于 CountDownLatch 类?

A:await()
B:countDown()
C:getCount()
D:release()

答:D
题目解析:release() 是 Semaphore 的释放许可的方法,CountDownLatch 类并不包含此方法。

4.CyclicBarrier 与 CountDownLatch 有什么区别?

答:CyclicBarrier 与 CountDownLatch 本质上都是依赖 volatile 和 CAS 实现的,它们区别如下:

  • CountDownLatch 只能使用一次,而 CyclicBarrier 可以使用多次。
  • CountDownLatch 是手动指定等待一个或多个线程执行完成再执行,而 CyclicBarrier 是 n 个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。

5.以下哪个类不包含 await() 方法?

A:Semaphore
B:CountDownLatch
C:CyclicBarrier

答:A

6.以下程序执行花费了多长时间?

Semaphore semaphore = new Semaphore(2);
ThreadPoolExecutor semaphoreThread = new ThreadPoolExecutor(10, 50, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
for (int i = 0; i < 3; i++) {
    semaphoreThread.execute(() -> {
        try {
            semaphore.release();
            System.out.println("Hello");
            TimeUnit.SECONDS.sleep(2);
            semaphore.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

A:1s 以内
B:2s 以上

答:A
题目解析:循环先执行了 release() 也就是释放许可的方法,因此程序可以一次性执行 3 个线程,同时会在 1s 以内执行完。

7.Semaphore 有哪些常用的方法?

答:常用方法如下:

  • acquire():获取一个许可。
  • release():释放一个许可。
  • availablePermits():当前可用的许可数。
  • acquire(int n):获取并使用 n 个许可。
  • release(int n):释放 n 个许可。

8.Phaser 常用方法有哪些?

答:常用方法如下:

  • register():注册新的参与者到 Phaser
  • arriveAndAwaitAdvance():等待其他线程执行
  • arriveAndDeregister():注销此线程
  • forceTermination():强制 Phaser 进入终止态
  • isTerminated():判断 Phaser 是否终止

9.以下程序是否可以正常执行?“发车了”打印了多少次?

import java.util.concurrent.*;
public class TestMain {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(4, new Runnable() {
            @Override
            public void run() {
                System.out.println("发车了");
            }
        });
        for (int i = 0; i < 4; i++) {
            new Thread(new CyclicWorker(cyclicBarrier)).start();
        }
    }
    static class CyclicWorker implements Runnable {
        private CyclicBarrier cyclicBarrier;

        CyclicWorker(CyclicBarrier cyclicBarrier) {
            this.cyclicBarrier = cyclicBarrier;
        }
        @Override
        public void run() {
            for (int i = 0; i < 2; i++) {
                System.out.println("乘客:" + i);
                try {
                    cyclicBarrier.await();
                    System.out.println("乘客 II:" + i);
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

答:可以正常执行,因为执行了两次 await(),所以“发车了”打印了 4 次。

总结

本文我们介绍了四种比 synchronized 更高级的线程同步类,其中 CountDownLatch、CyclicBarrier、Phaser 功能比较类似都是实现线程间的等待,只是它们的侧重点有所不同,其中 CountDownLatch 一般用于等待一个或多个线程执行完,才执行当前线程,并且 CountDownLatch 不能重复使用;CyclicBarrier 用于等待一组线程资源都进入屏障点再共同执行;Phaser 是 JDK 7 提供的功能更加强大和更加灵活的线程辅助工具,等待所有线程达到之后,继续或开始新的一组任务,Phaser 提供了动态增加和消除线程同步个数功能。而 Semaphore 提供的功能更像锁,用于控制一组资源的访问权限。


欢迎关注我的公众号,回复关键字“Java” ,将会有大礼相送!!! 祝各位面试成功!!!

%97%E5%8F%B7%E4%BA%8C%E7%BB%B4%E7%A0%81.png)

Guess you like

Origin www.cnblogs.com/dailyprogrammer/p/12272759.html