Chapter 14 Thread Tools

Semaphore

Semaphores are used to limit the number of threads that can access shared resources at the same time.

  • Semaphore is a counter that represents the number of currently available resources.
  • Two core operations P apply for resources and V is a resource release operation.
public class SemaphoreDemo {
    
    
    public static void main(String[] args) {
    
    
        Semaphore semaphore = new Semaphore(3);
        for (int i = 1; i <=6; i++) {
    
    
            new Thread(()->{
    
    
                try {
    
    
                    System.out.println(Thread.currentThread().getName()+"\t抢占了车位");
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"\t离开了车位");
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }finally {
    
    
                    semaphore.release();
                }
            },String.valueOf(i)).start();
        }
    }
}
2	抢占了车位
4	抢占了车位
4	离开了车位
6	抢占了车位
6	离开了车位
3	抢占了车位
3	离开了车位
1	抢占了车位
1	离开了车位
5	抢占了车位
2	离开了车位
5	离开了车位
  • acquire (acquire) When a thread calls the acquire operation, it either successfully acquires the semaphore (the semaphore is decremented by 1), or it waits until a thread releases the semaphore or times out.

  • release actually increases the value of the semaphore by 1 and then wakes up the waiting thread.

  • Semaphores are mainly used for two purposes, one is for mutually exclusive use of multiple shared resources, and the other is for controlling the number of concurrent threads.

CountDownLatch(Latch) does subtraction

Used for thread synchronization and cooperation, waiting for all threads to complete the countdown.

  • The construction parameters are used to initialize the wait count value, await() is used to wait for the count to return to zero, and countDown() is used to decrement the count by one.
public class CountDownLatchDemo {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        CountDownLatch countDownLatch=new CountDownLatch(6);
        for (int i = 1; i <=6; i++) {
    
    
            new Thread(()->{
    
    
                System.out.println(Thread.currentThread().getName()+"\t");
                countDownLatch.countDown();
            },i+"").start();
        }
        countDownLatch.await();
        System.out.println(Thread.currentThread().getName()+"\t班长关门走人,main线程是班长");

    }
}
1	
6	
5	
4	
3	
2	
main	班长关门走人,main线程是班长
  • CountDownLatch mainly has two methods. When one or more threads call the await method, these threads will block.
  • When other threads call the countDown method, the counter will be decremented by 1 (the thread calling the countDown method will not block)
  • When the counter value becomes 0, the thread blocked by the await method will be awakened and execution will continue.

CyclicBarrier does addition

CyclicBarrier literally means a barrier that can be used cyclically. What it does is to block a group of threads when they reach a barrier (also called a synchronization point). The barrier will not open until the last thread reaches the barrier, and all threads intercepted by the barrier will continue to work. The thread enters the barrier through the await() method of CyclicBarrier

public class CyclicBarrierDemo {
    
    
    public static void main(String[] args) {
    
    
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        CyclicBarrier cb = new CyclicBarrier(2,()->{
    
    
            System.out.println("任务完成");
        }); // 个数为2时才会继续执行
        for (int i = 0; i < 3; i++) {
    
    
            executorService.submit(()->{
    
    
                System.out.println(Thread.currentThread().getName()+"开始运行" +new Date());
                try {
    
    
                    cb.await(); // 当个数不足时,等待
                } catch (InterruptedException | BrokenBarrierException e) {
    
    
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"继续向下运行" +new Date());
            });
            executorService.submit(()->{
    
    
                System.out.println(Thread.currentThread().getName()+"开始运行" +new Date());
                try {
    
    
                    TimeUnit.SECONDS.sleep(2);
                    cb.await(); // 当个数不足时,等待
                } catch (InterruptedException | BrokenBarrierException e) {
    
    
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"继续向下运行" +new Date());
            });
        }

    }
}
pool-1-thread-2开始运行Sun Jul 02 13:45:56 CST 2023
pool-1-thread-1开始运行Sun Jul 02 13:45:56 CST 2023
任务完成
pool-1-thread-2继续向下运行Sun Jul 02 13:45:58 CST 2023
pool-1-thread-1继续向下运行Sun Jul 02 13:45:58 CST 2023
pool-1-thread-1开始运行Sun Jul 02 13:45:58 CST 2023
pool-1-thread-2开始运行Sun Jul 02 13:45:58 CST 2023
任务完成
pool-1-thread-2继续向下运行Sun Jul 02 13:46:00 CST 2023
pool-1-thread-1继续向下运行Sun Jul 02 13:46:00 CST 2023
pool-1-thread-2开始运行Sun Jul 02 13:46:00 CST 2023
pool-1-thread-1开始运行Sun Jul 02 13:46:00 CST 2023
任务完成
pool-1-thread-1继续向下运行Sun Jul 02 13:46:02 CST 2023
pool-1-thread-2继续向下运行Sun Jul 02 13:46:02 CST 2023
  • After both threads execute await, each thread executing await will be blocked. When two threads execute await, the two blocked threads will continue to execute.
    • After the two threads execute await, the output task is completed.
  • Note that the main difference between CyclicBarrier and CountDownLatch is that CyclicBarrier can be reused. CyclicBarrier can be likened to "the train is full of people"
  • The number of threads executing tasks here must be consistent with the count of CyclicBarrier, otherwise an error will occur, because what we define here is that both task 1 and task 2 will be executed before downward execution. If there are more than two threads, it may be that two are executed. Task 1 goes down

Exchanger

Exchanger is a tool class for collaboration between threads. Exchanger is used to exchange data between threads. It provides a synchronization point at which two threads can exchange data with each other . The two threads exchange data through the exchange method. If the first thread executes the exchange method first, it will wait for the second thread to also execute the exchange. When both threads reach the synchronization point, the two threads can exchange data. , and pass the data produced by this thread to the other party. Therefore, the key point of using Exchanger is that the paired threads use the exchange() method. When a pair of threads reaches the synchronization point, data will be exchanged. Therefore the thread objects of this utility class are paired.

  • The Exchanger class provides two methods, String exchange(V x): used for exchange, starting the exchange and waiting for another thread to call exchange;
  • String exchange (V x, long timeout, TimeUnit unit): used for exchange, start exchange and wait for another thread to call exchange, and set the maximum waiting time. When the waiting time exceeds timeout, it will stop waiting.
public class ExchangerDemo {

    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();

        final Exchanger exchanger = new Exchanger();
        executor.execute(new Runnable() {
            String data1 = "克拉克森,小拉里南斯";

            @Override
            public void run() {
                nbaTrade(data1, exchanger);
            }
        });


        executor.execute(new Runnable() {
            String data1 = "格里芬";

            @Override
            public void run() {
                nbaTrade(data1, exchanger);
            }
        });

        executor.execute(new Runnable() {
            String data1 = "哈里斯";

            @Override
            public void run() {
                nbaTrade(data1, exchanger);
            }
        });

        executor.execute(new Runnable() {
            String data1 = "以赛亚托马斯,弗莱";

            @Override
            public void run() {
                nbaTrade(data1, exchanger);
            }
        });

        executor.shutdown();
    }

    private static void nbaTrade(String data1, Exchanger exchanger) {
        try {
            System.out.println(Thread.currentThread().getName() + "在交易截止之前把 " + data1 + " 交易出去");
            Thread.sleep((long) (Math.random() * 1000));

            String data2 = (String) exchanger.exchange(data1);
            System.out.println(Thread.currentThread().getName() + "交易得到" + data2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
pool-1-thread-1在交易截止之前把 克拉克森,小拉里南斯 交易出去
pool-1-thread-2在交易截止之前把 格里芬 交易出去
pool-1-thread-3在交易截止之前把 哈里斯 交易出去
pool-1-thread-4在交易截止之前把 以赛亚托马斯,弗莱 交易出去
pool-1-thread-4交易得到格里芬
pool-1-thread-2交易得到以赛亚托马斯,弗莱
pool-1-thread-1交易得到哈里斯
pool-1-thread-3交易得到克拉克森,小拉里南斯

Guess you like

Origin blog.csdn.net/qq_50985215/article/details/131511153