多线程(十三、AQS原理-Semaphore信号量)

Semaphore介绍

Semaphore,限制对共享资源访问的最大线程数量,要访问共享资源,需要先申请许可,申请到许可才能访问。访问结果了,释放许可。

案例:

3个线程:Thread-1、Thread-2、Thread-3。一个许可数为2的公平策略的Semaphore。

线程的调用顺序如下:
Thread-1 申请一个许可,等待几秒钟,继续执行
Thread-2 申请2个许可,许可不足,阻塞
Thread-3 申请一个许可,等待几秒钟,继续执行
Thread-1,Thread-3,释放许可之后,Thread-2可以申请许可,成功执行。

代码:

Thread-1/3

import java.util.concurrent.Semaphore;

public class Task1 implements Runnable{

    private Semaphore semaphore;

    public Task1(Semaphore semaphore) {
        this.semaphore = semaphore;
    }

    @Override
    public void run() {

        try {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + "获取到许可....");
            Thread.sleep(3000);
            System.out.println(Thread.currentThread().getName() + "执行....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println(Thread.currentThread().getName() + "释放许可....");
            semaphore.release();
        }
    }
}

Thread-2

import java.util.concurrent.Semaphore;

public class Task2 implements Runnable{

    private Semaphore semaphore;

    public Task2(Semaphore semaphore) {
        this.semaphore = semaphore;
    }

    @Override
    public void run() {

        try {
            System.out.println(Thread.currentThread().getName() + "申请许可....");
            semaphore.acquire(2);
            System.out.println(Thread.currentThread().getName() + "获取到许可....");
            Thread.sleep(3000);
            System.out.println(Thread.currentThread().getName() + "执行....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println(Thread.currentThread().getName() + "释放许可....");
            semaphore.release(2);
        }
    }
}

启动文件

import java.text.ParseException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Main {

    public static void main(String[] args) throws ParseException, InterruptedException {
        Semaphore semaphore = new Semaphore(2, true);

        ReentrantLock lock = new ReentrantLock(true);
        Condition condition = lock.newCondition();
        Thread t1 = new Thread(new Task1(semaphore),"Thread-1");
        t1.start();
        Thread.sleep(2000);
        Thread t2 = new Thread(new Task2(semaphore),"Thread-2");
        Thread t3 = new Thread(new Task1(semaphore),"Thread-3");
        t2.start();
        t3.start();
    }
}

结果:

源码分析

创建公平的Semaphore,就是直接修改AQS的同步状态state

Thread-1,申请许可,执行AQS的acquireSharedInterruptibly

Semaphore是如何实现tryAcquireShared方法的


此时,Thread-1申请一个,是足够的,返回成功,然后持有许可,此时state=1。

Thread-2申请2个许可,但是state=1,不够的。

Thread-2会申请失败,进入doAcquireSharedInterruptibly

doAcquireSharedInterruptibly方法之前的文章也介绍过了,这里不再详细介绍,最终Thread-2被包装成节点放【等待队列】,同时需要设置【等待队列】头结点为SIGNAL状态,然后Thread-2阻塞了。

Thread-3申请一个许可,是成功的,然后持有许可,此时state=0.

Thread-1,释放了许可,则state=1;




然后执行doReleaseShared,设置头节点状态为0,准备唤醒后继节点,也就是Thread-2.

此时,可能Thread-3还没有释放许可,state=1,那么Thread-2又会被阻塞。

Thread-3,释放许可,state=2,继续唤醒Thread-2.

Thread-2,获取许可成功,state=0,继续执行。

Thread-2,释放许可,state=2,程序执行完成。

原文地址:https://blog.51cto.com/janephp/2411705

时间: 2024-10-11 08:43:29

多线程(十三、AQS原理-Semaphore信号量)的相关文章

AQS 原理以及 AQS 同步组件总结

1 AQS 简单介绍 AQS 的全称为(AbstractQueuedSynchronizer),这个类在 java.util.concurrent.locks 包下面. AQS 是一个用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出应用广泛的大量的同步器,比如我们提到的 ReentrantLock,Semaphore,其他的诸如 ReentrantReadWriteLock,SynchronousQueue,FutureTask 等等皆是基于 AQS 的.当然,我们自己也能利用 AQ

【C/C++多线程编程之七】pthread信号量

多线程编程之信号量 Pthread是 POSIX threads 的简称,是POSIX的线程标准. 互斥量用来处理一个共享资源的同步访问问题,当有多个共享资源时,就需要用到信号量机制.          信号量机制用于保证两个或多个共享资源被线程协调地同步使用,信号量的值对应当前可用资源的数量.          1.信号量(samaphore):         信号量机制通过信号量的值控制可用资源的数量.线程访问共享资源前,需要申请获取一个信号量,如果信号量为0,说明当前无可用的资源,线程无

多线程断点下载原理(java代码实例演示)

其实多线程断点下载原理,很简单的,那么我们就来先了解下,如何实现多线程的断点下载,首先:你必须明白第一点,那么就是,什么是多线程下载,该知识点可以查看本博客上一篇文章,Android之多线程下载原理,断点下载呢,其实就是在这个的基础之上添加了一些东西,那么添加了什么东西了,现在来做一个详细的了解. 1.在下载的过程中,边下载,变用一个文件来记录下载的位置,也就是下载了多少的数据 1.创建文件 2.记录下载多少数据 3.存储数据 2.第二次下载的时候,就去读取文件中是否存有数据,读取上次下载的位置

windows系统调用 semaphore信号量

1 #include "iostream" 2 #include "windows.h" 3 #include "cstring" 4 using namespace std; 5 6 HANDLE g_hSemThreads=INVALID_HANDLE_VALUE; 7 8 static DWORD WINAPI ThreadProc(LPVOID lpParam){ 9 LONG nPauseMs=reinterpret_cast<L

java多线程模式ThreadLocal原理简述及其使用详解

原创整理不易,转载请注明出处:java多线程模式ThreadLocal原理简述及其使用详解 代码下载地址:http://www.zuidaima.com/share/1781557457128448.htm ThreadLocal是为了使每个线程保存一份属于自己的数据. 先看一个使用ThreadLocal的实例. package com.zuidaima.aop.framework; import com.zuidaima.core.NamedThreadLocal; public abstra

java多线程断点下载原理(代码实例演示)

原文:http://www.open-open.com/lib/view/open1423214229232.html 其实多线程断点下载原理,很简单的,那么我们就来先了解下,如何实现多线程的断点下载,首先:你必须明白第一点,那么就是,什么是多线程下载,该知识点可以查看本博客上一篇文章,Android之多线程下载原理,断点下载呢,其实就是在这个的基础之上添加了一些东西,那么添加了什么东西了,现在来做一个详细的了解. 1.在下载的过程中,边下载,变用一个文件来记录下载的位置,也就是下载了多少的数据

Semaphore信号量

import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /**  * 信号量  *  * @author Vincent Zhao  * @version 1.0.0  * @Time 2015/4/20 15:57  */ public class SemaphoreDemo {     public st

【黑马Android】(07)多线程下载的原理/开源项目xutils/显示意图/隐式意图/人品计算器/开启activity获取返回值

多线程下载的原理 司马光砸缸,多开几个小水管,抢救小朋友. import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import

Semaphore(信号量)

Semaphore(信号量) 互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去. 互斥锁只有1把锁,信号量有多把锁. import threading, time def run(n): semaphore.acquire()#信号量获取 time.sleep(1) print("run the thread: %s\n" % n) semaphore.rele