Java并发编程的艺术(八)——闭锁、同步屏障、信号量详解

1. 闭锁:CountDownLatch

1.1 使用场景

若有多条线程,其中一条线程需要等到其他所有线程准备完所需的资源后才能运行,这样的情况可以使用闭锁。

1.2 代码实现

// 初始化闭锁,并设置资源个数
CountDownLatch latch = new CountDownLatch(2);

Thread t1 = new Thread( new Runnable(){
    public void run(){
        // 加载资源1
        加载资源的代码……
        // 本资源加载完后,闭锁-1
        latch.countDown();
    }
} ).start();

Thread t2 = new Thread( new Runnable(){
    public void run(){
        // 加载资源2
        资源加载代码……
        // 本资源加载完后,闭锁-1
        latch.countDown();
    }
} ).start();

Thread t3 = new Thread( new Runnable(){
    public void run(){
        // 本线程必须等待所有资源加载完后才能执行
        latch.await();
        // 当闭锁数量为0时,await返回,执行接下来的任务
        任务代码……
    }
} ).start();

2. 同步屏障:CyclicBarrier

2.1 使用场景

若有多条线程,他们到达屏障时将会被阻塞,只有当所有线程都到达屏障时才能打开屏障,所有线程同时执行,若有这样的需求可以使用同步屏障。此外,当屏障打开的同时还能指定执行的任务。

2.2 闭锁 与 同步屏障 的区别

  • 闭锁只会阻塞一条线程,目的是为了让该条任务线程满足条件后执行;
  • 而同步屏障会阻塞所有线程,目的是为了让所有线程同时执行(实际上并不会同时执行,而是尽量把线程启动的时间间隔降为最少)。

2.3 代码实现

// 创建同步屏障对象,并制定需要等待的线程个数 和 打开屏障时需要执行的任务
CyclicBarrier barrier = new CyclicBarrier(3,new Runnable(){
    public void run(){
        //当所有线程准备完毕后触发此任务
    }
});

// 启动三条线程
for( int i=0; i<3; i++ ){
    new Thread( new Runnable(){
        public void run(){
            // 等待,(每执行一次barrier.await,同步屏障数量-1,直到为0时,打开屏障)
            barrier.await();
            // 任务
            任务代码……
        }
    } ).start();
}

3. 信号量:Semaphore

3.1 使用场景

若有m个资源,但有n条线程(n>m),因此同一时刻只能允许m条线程访问资源,此时可以使用Semaphore控制访问该资源的线程数量。

3.2 代码实现

// 创建信号量对象,并给予3个资源
Semaphore semaphore = new Semaphore(3);

// 开启10条线程
for ( int i=0; i<10; i++ ) {
    new Thread( new Runnbale(){
        public void run(){
            // 获取资源,若此时资源被用光,则阻塞,直到有线程归还资源
            semaphore.acquire();
            // 任务代码
            ……
            // 释放资源
            semaphore.release();
        }
    } ).start();
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Phoenix的Android之旅

Dagger2 Android应用:接入

网上不少资源说要在Project和module下的build.gradle分别添加以下依赖,然而是错的

822
来自专栏pangguoming

Result Maps collection already contains value for ***

关于  MyBatis配置的时候,出现  Result Maps collection already contains value for ***  这个的问...

3636
来自专栏PHP在线

开始使用PHPUnit

想试一下单元测试很久了,但是一直没有合适的项目,而且中文网络上的PHPUnit教程要么太旧,要么太乱,所以总也没学会。最近准备把手头的项目重构一下,决定开始使用...

1333
来自专栏全栈之路

vscode配置go环境

假设目录为/Users/<用户名>/Documents/go-test,添加环境变量:

2853
来自专栏coding...

Jenkins + Android 自动化打包 发布到蒲公英写在前面准备工作新建任务签名配置一些报错

最先想到的方案当然就是跟iOS一样使用fastlane,查了下相关资料发现fastlane有点重iOS轻Android,于是放弃。找到代替方案,直接使用grad...

751
来自专栏小狼的世界

CentOs5.2中PHP的升级

最近一个项目中需要使用到PHP5.2的版本,而服务器上使用了官方的yum源进行安装,默认的版本是5.1.6,需要升级。但是因为不是一个非常正式的服务器环境,所以...

803
来自专栏封碎

合并apk和odex的方法 博客分类: Android小技巧 AndroidEXT工作

       有时候发现别人手机里有一款 apk 挺好,想弄出来装自己手机上,可是却发现那个 apk 是残缺的,里面没有 classes.dex 文件,却有个跟...

521
来自专栏Java学习123

linux mount -t用法

3125
来自专栏散尽浮华

Centos下SFTP双机高可用环境部署记录

SFTP(SSH File Transfer Protocol),安全文件传送协议。有时也被称作 Secure File Transfer Protocol 或...

3979
来自专栏灯塔大数据

15 个 Android 通用流行框架大全

? 1 缓存 名称描述DiskLruCacheJava实现基于LRU的磁盘缓存 2 图片加载 名称描述Android Universal Image Lo...

2916

扫码关注云+社区