来源:https://blog.csdn.net/carson0408/article/details/79475723
Semaphore是一种在多线程环境下使用的设施,该设施负责协调各个线程,以保证它们能够正确、合理的使用公共资源的设施,也是操作系统中用于控制进程同步互斥的量。Semaphore是一种计数信号量,用于管理一组资源,内部是基于AQS的共享模式。它相当于给线程规定一个量从而控制允许活动的线程数。
1.工作原理
以一个停车场是运作为例。为了简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆不受阻碍的进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入一辆,如果又离开两辆,则又可以放入两辆,如此往复。这个停车系统中,每辆车就好比一个线程,看门人就好比一个信号量,看门人限制了可以活动的线程。假如里面依然是三个车位,但是看门人改变了规则,要求每次只能停两辆车,那么一开始进入两辆车,后面得等到有车离开才能有车进入,但是得保证最多停两辆车。对于Semaphore类而言,就如同一个看门人,限制了可活动的线程数。
Semaphore主要方法:
Semaphore(int permits):构造方法,创建具有给定许可数的计数信号量并设置为非公平信号量。
Semaphore(int permits,boolean fair):构造方法,当fair等于true时,创建具有给定许可数的计数信号量并设置为公平信号量。
void acquire():从此信号量获取一个许可前线程将一直阻塞。相当于一辆车占了一个车位。
void acquire(int n):从此信号量获取给定数目许可,在提供这些许可前一直将线程阻塞。比如n=2,就相当于一辆车占了两个车位。
void release():释放一个许可,将其返回给信号量。就如同车开走返回一个车位。
void release(int n):释放n个许可。
int availablePermits():当前可用的许可数。
2.实例讲解
接下来举个例子,就是关于每个人的个人信息,那么一个人占用一个线程,并用Semphore类创建对象从而初始化信号量,控制可活动的线程数。具体代码如下:
package concurrent;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.LinkedBlockingQueue;
public class SemaphoreDemo {
private static final Semaphore semaphore=new Semaphore(3);
private static final ThreadPoolExecutor threadPool=new ThreadPoolExecutor(5,10,60,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
private static class InformationThread extends Thread{
private final String name;
private final int age;
public InformationThread(String name,int age)
{
this.name=name;
this.age=age;
}
public void run()
{
try
{
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+":大家好,我是"+name+"我今年"+age+"岁当前时间为:"+System.currentTimeMillis());
Thread.sleep(1000);
System.out.println(name+"要准备释放许可证了,当前时间为:"+System.currentTimeMillis());
System.out.println("当前可使用的许可数为:"+semaphore.availablePermits());
semaphore.release();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
public static void main(String[] args)
{
String[] name= {"李明","王五","张杰","王强","赵二","李四","张三"};
int[] age= {26,27,33,45,19,23,41};
for(int i=0;i<7;i++)
{
Thread t1=new InformationThread(name[i],age[i]);
threadPool.execute(t1);
}
}
}
运行上述程序结果如下:
pool-1-thread-3:大家好,我是张杰我今年33岁当前时间为:1520424000186
pool-1-thread-1:大家好,我是李明我今年26岁当前时间为:1520424000186
pool-1-thread-2:大家好,我是王五我今年27岁当前时间为:1520424000186
张杰要准备释放许可证了,当前时间为:1520424001187
李明要准备释放许可证了,当前时间为:1520424001187
王五要准备释放许可证了,当前时间为:1520424001187
当前可使用的许可数为:0
当前可使用的许可数为:0
当前可使用的许可数为:0
pool-1-thread-4:大家好,我是王强我今年45岁当前时间为:1520424001187
pool-1-thread-2:大家好,我是张三我今年41岁当前时间为:1520424001187
pool-1-thread-1:大家好,我是李四我今年23岁当前时间为:1520424001187
李四要准备释放许可证了,当前时间为:1520424002187
王强要准备释放许可证了,当前时间为:1520424002187
当前可使用的许可数为:0
张三要准备释放许可证了,当前时间为:1520424002187
pool-1-thread-5:大家好,我是赵二我今年19岁当前时间为:1520424002187
当前可使用的许可数为:0
当前可使用的许可数为:0
赵二要准备释放许可证了,当前时间为:1520424003188
当前可使用的许可数为:2
以上是非公平信号量,将建立Semaphore对象的语句改为如下语句:
private static final Semaphore semaphore=new Semaphore(3,true);
运行程序:
pool-1-thread-2:大家好,我是王五我今年27岁当前时间为:1520424286454
pool-1-thread-3:大家好,我是张杰我今年33岁当前时间为:1520424286454
pool-1-thread-1:大家好,我是李明我今年26岁当前时间为:1520424286454
pool-1-thread-1:李明要准备释放许可证了,当前时间为:1520424287455
当前可使用的许可数为:0
pool-1-thread-2:王五要准备释放许可证了,当前时间为:1520424287455
pool-1-thread-3:张杰要准备释放许可证了,当前时间为:1520424287455
当前可使用的许可数为:0
当前可使用的许可数为:1
pool-1-thread-1:大家好,我是李四我今年23岁当前时间为:1520424287455
pool-1-thread-5:大家好,我是赵二我今年19岁当前时间为:1520424287455
pool-1-thread-4:大家好,我是王强我今年45岁当前时间为:1520424287455
pool-1-thread-4:王强要准备释放许可证了,当前时间为:1520424288456
当前可使用的许可数为:0
pool-1-thread-1:李四要准备释放许可证了,当前时间为:1520424288456
pool-1-thread-3:大家好,我是张三我今年41岁当前时间为:1520424288456
pool-1-thread-5:赵二要准备释放许可证了,当前时间为:1520424288456
当前可使用的许可数为:0
当前可使用的许可数为:0
pool-1-thread-3:张三要准备释放许可证了,当前时间为:1520424289456
当前可使用的许可数为:2
3.实现单例模式
将创建信号量对象语句修改如下:
private static final Semaphore semaphore=new Semaphore(1);
运行程序,结果如下:
pool-1-thread-1:大家好,我是李明我今年26岁当前时间为:1520424379699
pool-1-thread-1:李明要准备释放许可证了,当前时间为:1520424380700
当前可使用的许可数为:0
pool-1-thread-2:大家好,我是王五我今年27岁当前时间为:1520424380700
pool-1-thread-2:王五要准备释放许可证了,当前时间为:1520424381701
当前可使用的许可数为:0
pool-1-thread-3:大家好,我是张杰我今年33岁当前时间为:1520424381701
pool-1-thread-3:张杰要准备释放许可证了,当前时间为:1520424382702
当前可使用的许可数为:0
pool-1-thread-4:大家好,我是王强我今年45岁当前时间为:1520424382702
pool-1-thread-4:王强要准备释放许可证了,当前时间为:1520424383702
当前可使用的许可数为:0
pool-1-thread-5:大家好,我是赵二我今年19岁当前时间为:1520424383702
pool-1-thread-5:赵二要准备释放许可证了,当前时间为:1520424384702
当前可使用的许可数为:0
pool-1-thread-1:大家好,我是李四我今年23岁当前时间为:1520424384702
pool-1-thread-1:李四要准备释放许可证了,当前时间为:1520424385702
当前可使用的许可数为:0
pool-1-thread-2:大家好,我是张三我今年41岁当前时间为:1520424385702
pool-1-thread-2:张三要准备释放许可证了,当前时间为:1520424386703
当前可使用的许可数为:0
如上可知,如果将给定许可数设置为1,就如同一个单例模式,即单个停车位,只有一辆车进,然后这辆车出来后,下一辆车才能进。
4.总结
Semaphore主要用于控制当前活动线程数目,就如同停车场系统一般,而Semaphore则相当于看守的人,用于控制总共允许停车的停车位的个数,而对于每辆车来说就如同一个线程,线程需要通过acquire()方法获取许可,而release()释放许可。如果许可数达到最大活动数,那么调用acquire()之后,便进入等待队列,等待已获得许可的线程释放许可,从而使得多线程能够合理的运行。
---------------------
java线程里面Lock、synchronized 都是互斥锁,只允许一个线程进行通信。但是semaphore是允许一组授权许可,每个线程都可以必须拿到一组授权许可才可以进行执行,否则只能等待。其他线程释放许可才可以,这里的一组授权许可可以是1个许可,也可以是多个许可。
例如:
package thread.semaphore; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class SemaphoreTest { public static void main(String[] args) { ExecutorService pool = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(3);//任务当中允许执行的最大许可数 for (int i = 0; i < 10; i++) { final int c = i; pool.execute(new Runnable() { @Override public void run() { try { semaphore.acquire();//每个线程进来都取一个许可 // semaphore.acquire(2);//每个线程进来都取2个许可 System.out.println(c+"已经获得许可证了,当前时间为:"+System.currentTimeMillis()); System.out.println("当前任务:"+c+"被"+Thread.currentThread().getName()+"执行啦!当前时间:"+System.currentTimeMillis()); Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { System.out.println(c+"要准备释放许可证了,当前时间为:"+System.currentTimeMillis()); semaphore.release();//每个线程都释放1个许可 // semaphore.release(2);//每个线程都是释放2个许可。注意的是如果释放的许可数小于每次取得的许可数则程序会死锁 System.out.println("当前可使用的许可数为:"+semaphore.availablePermits()); } } }); } pool.shutdown(); } }
开始的时候三个线程同时拿到授权。然后某个线程执行完成之后释放授权,另外一个等待的线程立即获得授权,保证每次并发最大也只有三个线程数。
注意:
release必须放在finally里面去执行,避免异常导致许可证不能被释放。
如果acquire(200)拿到的许可证太多,那么当前初始化也就只有3个许可证的话,那么该线程就会一直等待下去,不会执行。
如果release(200)释放的许可太大,那么下一次几乎所有的线程都可以拿到许可证,那么失去了许可证的意义了。
相关推荐
信号灯模型是并发编程中的一种常见机制,常用于线程间的同步与通信。在系统级芯片(System-on-a-Chip, SOC)上实现信号灯模型,可以有效地协调多个任务或线程,确保资源的安全访问和避免竞态条件。在本案例中,我们...
在多线程环境中,信号灯(Semaphore)是一种同步机制,用于控制多个线程对共享资源的访问,避免竞态条件的发生。本文将深入探讨在Linux Red Hat 7.0环境下如何使用信号灯,并以提供的`test.c`源代码为例进行解析。 ...
在Linux系统编程中,信号灯(Semaphore)是...在多线程或多进程环境中,信号灯是解决竞态条件和死锁的有效工具。通过理解并正确使用`mysem.c`和`mysem.h`中的代码,开发者可以更好地控制并发访问,实现高效的程序设计。
"信号灯法"(也称为信号量或Semaphore)是一种有效的方法,用于解决生产者与消费者问题,这种模式在并发编程中非常常见。下面我们将深入探讨这个主题。 **生产者与消费者模式** 是一个经典的多线程问题,涉及到两个...
接下来,我们来看“信号灯”(Semaphore)。信号灯是另一种同步机制,它允许特定数量的线程访问一个共享资源。当信号灯计数值大于0时,线程可以获取一个许可证并进入临界区;当计数值为0时,其他试图获取许可证的...
此外,还探讨了如何使用 semaphore 实现进程间的同步与互斥,通过实例解析展示了经典的多线程和进程间通讯问题,如生产者消费者模型、信号灯的应用场景及解决办法。 适合人群:对于有一定Linux系统操作基础的学生...
信号灯(Semaphore)是一种同步机制,用于控制多个线程访问共享资源的数量。信号灯可以设置一个初始值,表示可以访问资源的线程数量。当一个线程访问资源时,需要执行 P 操作(wait 操作),将信号灯的值减 1;当...
Semaphore,顾名思义,就像是一个信号灯或通行证,用来管理一组有限的资源。在Java中,Semaphore类提供了对并发线程进行计数的许可管理,允许我们限制同时访问特定资源的线程数量。这在处理并发任务时非常有用,例如...
在本场景中,“多线程控制红绿灯变化”是一个典型的并发编程问题,旨在模拟现实生活中交通信号灯的交替工作模式。这个系统设计通常涉及两个主要线程,一个负责控制红灯,另一个负责控制绿灯,它们需要按照特定的时间...
在点灯示例中,可能有多个线程试图控制LED灯。通过使用信号量,我们可以确保每次只有一个线程能改变LED的状态,防止闪烁或混乱。线程A负责点亮LED,线程B负责熄灭LED。它们都会尝试获取信号量,只有成功获取到信号量...
在多线程控制中,信号量是一个关键的概念,用于协调多个线程对共享资源的访问,从而避免了竞态条件和死锁等问题。本文将深入探讨易语言中的信号量控制线程数量这一主题。 首先,我们需要理解什么是线程。线程是程序...
综上所述,这个Java交通信号灯模拟项目涵盖了多线程编程、并发控制、异常处理和单元测试等多个关键的Java编程知识点,是学习和实践Java技术的好案例。通过阅读和分析这个项目,开发者可以深入理解Java并发编程的核心...
然后,报告详细介绍了使用多线程解决读者阅览问题的步骤,包括创建reader函数、使用信号灯判断座位是否被坐满、实现上锁操作、找座位坐下、阅读、打印座位信息、当前读者离开座位、读者注销等步骤。报告最后还对课程...
在Dijkstra的模型中,信号如同铁路信号灯,控制着单线轨道上的火车通行。在计算机术语中,信号量是一个简单的整数值,线程通过P(prolagen,尝试减少)和V(verhogen,增加)操作来管理信号量,以确保对共享资源的...
在现实生活中,交通信号灯通过红、黄、绿三种颜色的交替控制交通流,避免交通堵塞。在哲学家的晚餐问题中,我们可以将筷子看作是交通信号灯,通过设置状态来控制哲学家取放筷子的行为。 在CenaFilosofos项目中,每...
许可证,也称为信号灯或信号量,是多线程同步的一种机制,用于限制对共享资源的并发访问。它是一个整数值,当值为正时,表示可用许可证的数量;当值为零时,其他试图获取许可证的线程将被阻塞,直到有线程释放许可证...
8. **Semaphore**:信号灯,可以控制同时访问特定资源的线程数量,与互斥量类似,但更灵活,可以控制多个线程同时访问。 在实际编程中,选择哪种同步机制取决于具体的需求。例如,如果需要确保某个资源只被一个线程...
常见的同步机制包括互斥量(Mutex)、信号量(Semaphore)、事件(Event)、临界区(Critical Section)以及线程局部存储(TLS)等。 3. **死锁**:当两个或更多线程相互等待对方释放资源时,就会发生死锁。避免...
- 信号灯(Semaphore):理解信号灯作为进程间通信(IPC)的一种工具,用于解决资源的互斥访问和同步问题。 #### 1.2 实验过程 - **预备知识**:复习线程的基本概念,如线程的生命周期、调度和同步。 - **实验测试...