并发编程(七)Tool

简介: 并发编程(七)Tool

Semaphore

Semaphore 字面意思是信号量的意思,它的作用是控制访问特定资源的线程数目。获取释放资源详细流程

简单使用

  1. 构造方法
  • public Semaphore(int permits)
  • public Semaphore(int permits, boolean fair)

permits:可用的初始许可证数量,用来控制同时可加锁线程的数量

fair:true表示创建一个公平锁,false表示创建一个非公平锁,默认创建非公平锁

  1. 主要方法
  • acquire() 用于获取许可资源
  • release() 用于释放许可资源
  1. 代码演示

应用场景:资源访问,服务限流。

public class Semaphoretest {
    public static Semaphore semaphore = new Semaphore(2);
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(Semaphoretest::semaphoreTest, "thread-" + i).start();
        }
    }
    public static void semaphoreTest() {
        try {
            //可加锁次数为semaphore初始值,若超过则等待释放锁
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName()+"获得了锁");
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println(Thread.currentThread().getName()+"释放了锁");
            semaphore.release();
        }
    }
}

CountDownLatch

CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。

实现原理

CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。

简单使用

  1. 构造方法
  • public CountDownLatch(int count) count为计数器的初始值(资源的初始值)
  1. 主要方法
  • countDown(); 这里主要是在做释放资源(count-1)的操作(解锁),每次释放都会唤醒阻塞线程。
  • await(); 这里主要在做加锁操作,判断条件为资源池的资源不为0就表示加锁失败,入队阻塞。
  1. 代码演示
public class CountDownLatchTest {
       public static CountDownLatch countDownLatch = new CountDownLatch(2);
       public static void main(String[] args) throws InterruptedException {
           new Thread(()->{
               for (int i = 0; i < 10; i++) {
                   try {
                       TimeUnit.SECONDS.sleep(1);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   new Thread(CountDownLatchTest::countDownLatchTest, "thread-" + i).start();
               }
           }).start();
           System.out.println("等待任务结束");
           //当countDown数达到CountDownLatch初始化值,则结束等待
           countDownLatch.await();
           System.out.println("任务结束");
       }
       public static void countDownLatchTest() {
           try {
               System.out.println(Thread.currentThread().getName()+"开始执行任务");
               TimeUnit.SECONDS.sleep(3);
           } catch (InterruptedException e) {
               e.printStackTrace();
           } finally {
               System.err.println(Thread.currentThread().getName()+"执行任务完毕");
               countDownLatch.countDown();
           }
       }
   }

CyclicBarrier

栅栏屏障,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。

应用场景

可以用于多线程计算数据,最后合并计算结果的场景。例如,用一个Excel保存了用户 所有银行流水,每个Sheet保存一个账户近一年的每笔银行流水,现在需要统计用户的日均银行流水,先用多线程处理每个sheet里的银行流水,都执行完之后,得到每个sheet的日均银行流水,最后,再用barrierAction用这些线程的计算结果,计算出整个Excel的日均银行流水。

简单使用

  1. 构造方法
  • CyclicBarrier(int parties) 其参数表示屏障拦截的线程数量,每个线程调用await方法告CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。
  • public CyclicBarrier(int parties, Runnable barrierAction) 当所有线程都到达屏障时,会调用一次barrierAction
  1. 主要方法
  • await()
  1. 代码演示
public class CyclicBarrierTest {
    public static CyclicBarrier cyclicBarrier = new CyclicBarrier(10, () -> {
        System.out.println("hello");
    });
    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                try {
                    //当await数达到CyclicBarrier初始化的parties值,则调用一次CyclicBarrier中的Run方法
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

注意,若调用await()方法的线程达不到初始值,则会一直陷入阻塞

目录
相关文章
|
2月前
|
缓存 NoSQL Go
通过 SingleFlight 模式学习 Go 并发编程
通过 SingleFlight 模式学习 Go 并发编程
|
2月前
|
设计模式 安全 Go
深入探索 Go 语言中的并发编程
并发编程是现代软件开发中的重要组成部分,尤其是在多核处理器普及的今天,如何高效地利用硬件资源成为关键。Go 语言以其内置的并发支持而闻名,使得开发者能够轻松构建高性能、可扩展的应用程序。本文将深入探讨 Go 语言中的并发模型,涵盖 Goroutines、Channels 的使用,并讨论常见的并发陷阱及如何避免。
|
5月前
|
缓存 安全 Java
go并发编程
go的GMP并发模型,让go天然支持高并发,先了解一下GMP模型吧 GMP G协程,M工作线程、P处理器,M必须持有P才可以执行G P维护着一个协程G队列,P依次将G调度到M中运行 if M0中G0发生系统调用,M0将释放P,冗余的M1获取P,继续执行P队列中剩余的G。(只要P不空闲就充分利用了CPU) G0系统调用结束后,如果有空闲的P,则获取P继续执行G0,否则将G0放入全局队列,M0进入缓存池睡眠。(全局队列中的G主要来自从系统调用中恢复的G) 下面介绍一下编程常用的同步(synchronize)原语 互斥锁 mutex rwmutex,要了解自旋和饥饿模式 自旋最多4次,cpu核
53 1
|
5月前
|
存储 Go
【Go 语言专栏】Go 语言的并发编程基础:goroutines 与 channels
【4月更文挑战第30天】Go 语言的并发编程基于goroutines和channels。Goroutines是轻量级线程,低成本并发执行。创建goroutine只需在函数调用前加`go`。Channels作为goroutines间通信和同步的桥梁,分无缓冲和有缓冲两种,可用`make`创建。结合使用goroutines和channels,可实现数据传递和同步,如通过无缓冲channels实现任务同步,或通过有缓冲channels传递数据。注意避免死锁、资源竞争,合理使用缓冲,以发挥Go并发优势。
34 1
|
5月前
|
缓存 安全 程序员
Python 的并发编程:解释什么是线程安全(Thread Safety)?
Python 的并发编程:解释什么是线程安全(Thread Safety)?
175 1
上篇:Go并发编程
上篇:Go并发编程
79 0
|
缓存 安全 Java
Java Concurrencyin Practice 并发编程实践系列 第二章 线程安全 Thread Safety 下
Java Concurrencyin Practice 并发编程实践系列 第二章 线程安全 Thread Safety 下
|
存储 缓存 安全
Java Concurrencyin Practice 并发编程实践系列 第二章 线程安全 Thread Safety 上
Java Concurrencyin Practice 并发编程实践系列 第二章 线程安全 Thread Safety 上
|
设计模式 算法 安全
Java Concurrencyin Practice 并发编程实践系列1
Java Concurrencyin Practice 并发编程实践系列1
119 0
|
安全 Go 调度
go的并发编程
go的并发编程
98 0
go的并发编程