The use of multi-threaded programming auxiliary classes CountDownLatch, CyclicBarrier and Semaphore

Above, we mainly talked about thread pool related knowledge. This article mainly talks about auxiliary classes that are used with thread pool: CountDownLatch, CyclicBarrier and Semaphore.

1. CountDownLatch

CountDownLatch exists in the java.util.cucurrent package and literally means countdown lock.

  • The countDownLatch class allows a thread to wait for the execution of other threads before executing.

  • This function is realized through the attribute of an internal counter. Whenever a thread is executed, the countDown() method is called, and the value of the counter is -1. When the value of the counter is 0, it means that all threads have finished executing, and then the threads waiting on the lock can resume work.

1.1 The construction method provided in the CountDownLatch class:

//参数count为计数值
public CountDownLatch(int count) {
    
      };  

1.2 Important methods of the CountDownLatch class:

//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public void await() throws InterruptedException {
    
     };   
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
    
     };  
//将count值减1
public void countDown() {
    
     };  

1.3 Sample code of CountDownLatch:

One to one object in a list, with pagesize as the unit, open multiple threads to check the database assignment processing, and get the corresponding results.

public class Threads {
    
    
    public static void main(String[] args) throws Exception{
    
    
        //定义的一次查库的数量
        int pagesize = 3;
        //获取需要赋值的user集合
        List<User> list = getUserList();
        //计算需要并发的线程数
        int count = (list.size() + pagesize - 1) / pagesize;
        System.out.println("处理"+list.size()+"条数据,需要count:"+count+"个线程执行");
        List<User> newList = new ArrayList<>();
        //固定线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(count);
        CountDownLatch countDownLatch = new CountDownLatch(count);
        for (int i = 0; i < list.size(); i = i+pagesize) {
    
    
            TaskService ts = new TaskService(countDownLatch,list.subList(i,i+pagesize<=list.size()?i+pagesize:list.size()));
            //获取处理结果
            newList.addAll(threadPool.submit(ts).get());
        }
        try {
    
    
            //等待所有线程执行完毕
            countDownLatch.await();
        } catch (InterruptedException e) {
    
    
            System.out.println("InterruptedException exception"+e);
            Thread.currentThread().interrupt();
        } finally {
    
    
            threadPool.shutdown();
        }
       //输赋值后的结果
        for (User user: newList) {
    
    
            System.out.println(user.getName()+"_"+user.getAge());
        }
    }
    public static List<User> getUserList(){
    
    
        List<User> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
    
    
            String name = "user"+i;
            list.add(new User(name));
        }

        return list;
    }
}

class TaskService implements Callable<List<User>> {
    
    
    private CountDownLatch countDownLatch;
    private List<User> userList;
    TaskService(CountDownLatch countDownLatch,List<User> userList){
    
    
        this.countDownLatch = countDownLatch;
        this.userList = userList;
    }


    @Override
    public List<User> call() throws Exception {
    
    
        int age = 1;
       try{
    
    
           //模拟查库,循环赋值
           for (User u: userList) {
    
    
               u.setAge(age++);
           }
       }finally {
    
    
           //调用方法计数器减1
           countDownLatch.countDown();
        }
        return userList;
    }
}

operation result:

Insert picture description here

二.CyclicBarrier

From the literal meaning, we can know that the Chinese meaning of this category is "circular fence". It roughly means a recyclable barrier.

Its role is to make all threads wait for completion before proceeding to the next step.

2.1 The construction method provided by CyclicBarrier

public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)

parties is the number of threads involved

The second construction method has a Runnable parameter, which means the task to be the last to reach the thread

1.2 Important methods of the CyclicBarrier class:

public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException

Analysis:

  • await() is used to suspend the current thread. When the thread calls await(), it means that it has reached the barrier state.
  • The second version is to let these threads wait for a certain period of time. If there are threads that have not reached the barrier state, the threads that reach the barrier will directly perform subsequent tasks.

2.3 Sample code of CyclicBarrier class:

public class CyclicBarrierDemo {
    
    
    public static void main(String[] args) {
    
    
        int count = 3;
        //固定线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(count);
        CyclicBarrier cb = new CyclicBarrier(count, ()-> {
    
    
                System.out.println(Thread.currentThread().getName()+"所有线程到达栏栅状态!");
        });
        for (int i = 0; i < count; i++) {
    
    
            threadPool.submit(new CyclicBarrierTask(cb));
            Thread.sleep(1000L);
        }
        threadPool.shutdown();
    }
}

class CyclicBarrierTask implements Runnable{
    
    
    private CyclicBarrier cb;
    public CyclicBarrierTask(CyclicBarrier cb){
    
    
        this.cb = cb;
    }
    @Override
    public void run() {
    
    
        System.out.println(Thread.currentThread().getName()+"开始执行...");
        try {
    
    
            Thread.sleep(1000L);
            System.out.println(Thread.currentThread().getName()+"到达栅栏状态!");
            cb.await();
            System.out.println(Thread.currentThread().getName()+"执行结束。。。");
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
}

Results of the:

Insert picture description here

If we transform the 28 lines of the example code above into

cb.await(1000L,TimeUnit.MILLISECONDS);

You will see that after waiting for the specified time and finding that the threads have not all reached the barrier, an exception will be thrown and the following tasks will continue.

Insert picture description here

2.4 CyclicBarrier usage scenarios

It can be used to calculate data in multiple threads and finally merge the calculation results. Or you need to wait for the tasks of each thread to complete before you can continue the operation, such as storing multiple data tables at the same time.

2.5 The difference between CyclicBarrier and CountDownLatch

  • CountDownLatch is one-time, CyclicBarrier is recyclable
  • The responsibilities of the threads involved in CountDownLatch are different, some are counting down, and some are waiting for the countdown to end. CyclicBarrier participates in the same thread responsibilities.

三.Semaphore

Semaphore is translated literally as a semaphore. Semaphore can control the number of threads that are accessed at the same time. Acquire a permission through acquire(), and wait if not, while release() releases a permission.

3.1 The construction method provided by Semaphore

public Semaphore(int permits) {
    
              //参数permits表示许可数目,即同时可以允许多少线程进行访问
    sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
    
        //这个多了一个参数fair表示是否是公平的,即等待时间越久的越先获取许可
    sync = (fair)? new FairSync(permits) : new NonfairSync(permits);
}

2.3 Important methods of the Semaphore class:

public void acquire() throws InterruptedException {
    
      }     //获取一个许可
public void acquire(int permits) throws InterruptedException {
    
     }    //获取permits个许可
public void release() {
    
     }          //释放一个许可
public void release(int permits) {
    
     }    //释放permits个许可

​ acquire() is used to obtain a permit. If no permit can be obtained, it will wait until the permit is obtained.

release() is used to release the license. Note that before releasing the license, you must first obtain the license.

These four methods will all be blocked. If you want to get the execution result immediately, you can use the following methods:

public boolean tryAcquire() {
    
     };    //尝试获取一个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException {
    
     };  //尝试获取一个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false
public boolean tryAcquire(int permits) {
    
     }; //尝试获取permits个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException {
    
     }; //尝试获取permits个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false

In addition, you can get the number of available permits through the availablePermits() method.

If a factory has 5 machines but 8 workers, a machine can only be used by one worker at the same time, and other workers can continue to use it only when it is used up. Then we can achieve it through Semaphore:

2.4 Sample code of the Semaphore class:

ublic class Test {
    
    
    public static void main(String[] args) {
    
    
        int N = 8;            //工人数
        Semaphore semaphore = new Semaphore(5); //机器数目
        for(int i=0;i<N;i++)
            new Worker(i,semaphore).start();
    }
     
    static class Worker extends Thread{
    
    
        private int num;
        private Semaphore semaphore;
        public Worker(int num,Semaphore semaphore){
    
    
            this.num = num;
            this.semaphore = semaphore;
        }
         
        @Override
        public void run() {
    
    
            try {
    
    
                semaphore.acquire();
                System.out.println("工人"+this.num+"占用一个机器在生产...");
                Thread.sleep(2000);
                System.out.println("工人"+this.num+"释放出机器");
                semaphore.release();           
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}

Insert picture description here

to sum up:

1) Both CountDownLatch and CyclicBarrier can achieve waiting between threads, but they have different focuses:

CountDownLatch is generally used for a thread A to wait for several other threads to perform tasks before it executes;

And CyclicBarrier generally used for a group of threads wait for each other to a certain state, and then execute that group of threads simultaneously;

In addition, CountDownLatch cannot be reused, while CyclicBarrier can be reused.

2) Semaphore is actually similar to a lock. It is generally used to control access to a certain set of resources.

Guess you like

Origin blog.csdn.net/weixin_43828467/article/details/114377075