Semaphore, CountDownLatch, CyclicBarrier of thread collaboration tools

Various thread collaboration tools

Common thread collaboration tools:

  • ReadWriteLock ReadWriteLock
  • Semaphore
  • CountDownLatch
  • CyclicBarrier
  • Thread local variable ThreadLocal

Mainly talk about semaphore Semaphore, countdown latch CountDownLatch, CyclicBarrier and then apply it according to the two LeetCode topics.

first question:

Three different threads will share a single Foo instance.

Thread A will call the one() method Thread B will call the two() method Thread C will call the three() method Please design and modify the program to ensure that the two() method is executed after the one() method, three() The method is executed after the two() method.

Primitive solution

Application scenarios and usage

Based on notify/wait, all notification-like mechanisms for inter-thread communication are essentially notifyAll, which can be used for many purposes.


class Foo {
  private static AtomicInteger flag = new AtomicInteger(0);
    private static Object Lock1 = new Object();
    public Foo() {

    }

    public void first(Runnable printFirst) throws InterruptedException {
        synchronized (Lock1){
            printFirst.run();
            flag.set(2);
            Lock1.notifyAll();
        }
    }

    public void second(Runnable printSecond) throws InterruptedException {
        synchronized (Lock1){
            while (flag.get() != 2){
                Lock1.wait();
            }
            printSecond.run();
            flag.set(3);
            Lock1.notifyAll();
        }
    }

    public void third(Runnable printThird) throws InterruptedException {
        synchronized (Lock1){
            while (flag.get() != 3){
                Lock1.wait();
            }
            printThird.run();
            flag.set(4);
            Lock1.notifyAll();
        }
    }
}

Countdown door bolt solution

Application scenarios and usage
  • start at the same time. Initialize the CountDownLatch count to 1, the child thread and the main thread share the CountDownLatch variable, first start the child thread, then call the await method, the main thread calls the countDown method, that is, all child threads start at the same time.
  • Master-slave collaboration. The main thread relies on the running results of the sub-threads, initializes the CountDownLatch count to the number of sub-threads opened, and then calls the await method to wait. After the sub-threads have finished running the logic, they call the countDown method, so that the main thread waits for all sub-threads to complete before continuing to run.

class Foo {
    private CountDownLatch c2;
    private CountDownLatch c3;
    public Foo() {
         c2 = new CountDownLatch(1);
         c3 = new CountDownLatch(1);
    }
    
    public void first(Runnable printFirst) throws InterruptedException {
        printFirst.run();
        c2.countDown();
    }

    public void second(Runnable printSecond) throws InterruptedException {
        c2.await();
        printSecond.run();
        c3.countDown();
    }

    public void third(Runnable printThird) throws InterruptedException {
        c3.await();
        printThird.run();
    }
}

Semaphore solution

Application scenarios and usage
usage:

Pass in the new key Semaphore object of the number of licenses, which can be set whether it is fair or not

Get permission methods, there are blocking and non-blocking methods, there are responsive and non-responsive interrupt methods

The method is executed to release the permission

Application scenarios
  • Limit the number of concurrent accesses
  • It can also be used to build barriers between threads, because releasing the permission does not require the current thread to release it, any thread can call the release() method to release the permission.
public class Foo {
    //声明两个 Semaphore变量
    private Semaphore spa,spb;
    public Foo() {
        //初始化Semaphore为0的原因:如果这个Semaphore为零,如果另一线程调用(acquire)这个Semaphore就会产生阻塞,便可以控制second和third线程的执行
        spa = new Semaphore(0);
        spb = new Semaphore(0);
    }
    public void first(Runnable printFirst) throws InterruptedException {
            printFirst.run();
            //只有等first线程释放Semaphore后使Semaphore值为1,另外一个线程才可以调用(acquire)
            spa.release();
    }
    public void second(Runnable printSecond) throws InterruptedException {
            spa.acquire();
            printSecond.run();
            spb.release();
    }
    public void third(Runnable printThird) throws InterruptedException {
            spb.acquire();
            printThird.run();
    }
}

Second question:

There are now two threads, hydrogen and oxygen, and your goal is to organize both threads to produce water molecules.

There is a barrier so that each thread must wait until a complete water molecule can be produced.

Hydrogen and oxygen threads are given the releaseHydrogen and releaseOxygen methods respectively to allow them to break through the barrier.

These threads should break through the barrier in groups of three and immediately combine to produce a water molecule.

You have to ensure that the binding of the threads required to produce one water molecule must occur before the next water molecule is produced.

in other words:

If an oxygen thread reaches the barrier and no hydrogen threads arrive, it must wait until two hydrogen threads arrive. If one hydrogen thread reaches the barrier and no other threads arrive, it must wait until one oxygen thread and another hydrogen thread arrive. Write hydrogen and oxygen thread synchronization code that satisfies these constraints.

 

Example 1:

Input: "HOH" Output: "HHO" Explanation: "HOH" and "OHH" are still valid solutions. Example 2:

Input: "OOHHHH" Output: "HHOHHO" Explanation: "HOHHHO", "OHHHHO", "HHOHOH", "HOHHOH", "OHHHOH", "HHOOHH", "HOHOHH" and "OHHOHH" are still valid solutions.  

limitation factor:

The total length of the input string will be 3n, 1 ≤ n ≤ 50; the total number of "H"s in the input string will be 2n; the total number of "O"s in the input string will be n.

Usage and application scenarios of circular fence
usage

Initialize CyclicBarrier, pass in the number of threads to be blocked by the fence (you can also pass in a Runnable interface implementation, which will be executed by the last thread that reaches the rendezvous point),

Application scenarios

Multiple threads wait for each other, reach a rendezvous point, and then execute subsequent tasks.

solution:

class H2O {
    Semaphore semaphore4H = new Semaphore(2);
    Semaphore semaphore4O = new Semaphore(1);
    CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new Runnable() {
       @Override
       public void run() {
           semaphore4H.release(2);
           semaphore4O.release(1);
       }
   });
    public H2O() {

    }

    public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
        try {
            semaphore4H.acquire();
            releaseHydrogen.run();
            cyclicBarrier.await();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }

    }

    public void oxygen(Runnable releaseOxygen) throws InterruptedException {
        try {
            semaphore4O.acquire();
            releaseOxygen.run();
            cyclicBarrier.await();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}

{{o.name}}
{{m.name}}

Guess you like

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