深耕 JDK 源码 - Semaphore

在 Java 并发编程中,Semaphore(信号量)是一种用于控制资源访问和线程协作的多线程工具。它允许多个线程同时访问某个共享资源,但限制同时访问的线程数量,从而实现对并发访问的控制。Semaphore 是 Java 并发包(java.util.concurrent)中提供的一个类,从 JDK5 开始引入,并在 JDK8 中进行了一些改进。

Semaphore 的实现原理

Semaphore 的实现原理基于计数器和同步器的概念。Semaphore 内部维护一个计数器,该计数器表示当前可用的许可数量。线程可以通过调用 Semaphore 的 acquire() 方法来请求获取许可,如果当前许可数量大于0,则线程会获取到许可并将许可数量减一;否则,线程将被阻塞直到有可用许可。当线程完成访问共享资源后,需要通过调用 Semaphore 的 release() 方法来释放许可,从而增加许可数量,供其他线程继续获取。

Semaphore 还支持公平性和非公平性两种模式,默认是非公平模式。在公平模式下,线程会按照请求的顺序获取许可,而在非公平模式下,线程可能会通过竞争直接获取许可,从而导致某些线程获取到更多的许可。

Semaphore 的常见用法

Semaphore 在多线程编程中有很多常见的用法,包括但不限于以下几种:

1.限制并发访问数量:

Semaphore 可以用来限制同时访问某个共享资源的线程数量。通过设置 Semaphore 的许可数量,可以控制允许同时访问资源的线程数量,从而避免资源的过度竞争和争夺。例如,一个数据库连接池可以使用 Semaphore 来限制同时访问数据库的连接数量,从而避免数据库连接过多导致性能下降。

import java.util.concurrent.Semaphore;

public class ConnectionPool {
    private final Semaphore semaphore;
    // 初始化连接池
    public ConnectionPool(int poolSize) {
        semaphore = new Semaphore(poolSize);
        // 初始化连接
    }

    // 获取数据库连接
    public Connection getConnection() throws InterruptedException {
        semaphore.acquire();
        // 获取连接
    }

    // 释放数据库连接
    public void releaseConnection(Connection connection) {
        // 释放连接
        semaphore.release();
    }
}

2.控制线程的执行顺序

Semaphore 可以用来控制线程的执行顺序,通过设置 Semaphore 的许可数量为1,可以实现一种互斥的机制,即同一时刻只允许一个线程执行特定的代码段,从而实现对线程的顺序控制。例如,多个线程需要按照特定的顺序执行某些操作,可以使用 Semaphore 来实现。

import java.util.concurrent.Semaphore;

public class ThreadExecutionOrder {
    private final Semaphore semaphore = new Semaphore(1);
    private int currentThread = 1;

    public void thread1() throws InterruptedException {
        while (true) {
            semaphore.acquire();
            if (currentThread == 1) {
                System.out.println("Thread 1");
                currentThread = 2;
                semaphore.release();
                break;
            }
            semaphore.release();
        }
    }

    public void thread2() throws InterruptedException {
        while (true) {
            semaphore.acquire();
            if (currentThread == 2) {
                System.out.println("Thread 2");
                currentThread = 3;
                semaphore.release();
                break;
            }
            semaphore.release();
        }
    }

    public void thread3() throws InterruptedException {
        while (true) {
            semaphore.acquire();
            if (currentThread == 3) {
                System.out.println("Thread 3");
                currentThread = 1;
                semaphore.release();
                break;
            }
            semaphore.release();
        }
    }
}

3.实现线程间的协作

Semaphore 可以用来实现线程间的协作,通过设置 Semaphore 的初始许可数量和后续的许可获取和释放操作,可以实现线程的等待和唤醒操作,从而实现线程间的同步和协作。

import java.util.concurrent.Semaphore;

public class ThreadCooperation {
    private final Semaphore semaphore = new Semaphore(0);
    private boolean flag = false;

    public void printNumbers() throws InterruptedException {
        while (!flag) {
            semaphore.acquire();
            System.out.println("Printing numbers...");
            // 执行打印数字的操作
            semaphore.release();
            Thread.sleep(1000);
        }
    }

    public void signalPrintingComplete() {
        // 执行打印完成的操作
        flag = true;
        semaphore.release();
    }
}

4.控制资源的使用权限

Semaphore 还可以用来控制资源的使用权限,例如,限制同时访问某个资源的线程数量,或者限制某个资源的使用时间。通过合理设置 Semaphore 的许可数量和许可获取和释放操作,可以实现对资源的权限控制。

import java.util.concurrent.Semaphore;

public class ResourceAccessControl {
    private final Semaphore semaphore = new Semaphore(1);

    public void accessResource() throws InterruptedException {
        semaphore.acquire();
        // 访问资源
        Thread.sleep(1000);
        semaphore.release();
    }
}

这只是 Semaphore 的一些常见用法,实际上,Semaphore 还有很多其他的应用场景,可以根据实际需求进行灵活使用。

总结:

JDK8 中的 Semaphore 是一种用于控制资源访问和线程协作的多线程工具,其实现原理基于计数器和同步器的概念。Semaphore 可以用于限制并发访问数量、控制线程的执行顺序、实现线程间的协作以及控制资源的使用权限。通过合理设置 Semaphore 的许可数量和许可获取/释放操作,可以实现对多线程程序的高效管理和控制。

Semaphore 的使用方式相对简单,但需要注意以下几点:

1、在使用 Semaphore 时,应合理设置初始许可数量,确保许可的获取和释放操作能够满足实际需求,避免死锁或资源饥饿的情况。
2、在使用 Semaphore 进行线程协作时,需要谨慎处理信号量的获取和释放操作,避免出现竞态条件或错误的信号传递。
3、Semaphore 是可重入的,允许同一个线程多次获取许可,但需要注意合理管理许可的获取和释放,避免出现资源过度占用或过度释放的情况。
4、Semaphore 是基于计数器的概念,因此需要确保在每次许可获取后都能正确释放许可,避免许可泄漏导致资源无法再次被访问。

在多线程编程中,Semaphore 是一种强大的工具,能够在复杂的并发场景中提供灵活的资源管理和线程协作能力。合理使用 Semaphore 可以帮助开发者避免多线程并发问题,并提高多线程程序的性能和可靠性。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容