`
747017186
  • 浏览: 331402 次
社区版块
存档分类
最新评论

Semaphore信号灯控制线程

 
阅读更多

来源: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)释放的许可太大,那么下一次几乎所有的线程都可以拿到许可证,那么失去了许可证的意义了。

  • 大小: 68.2 KB
分享到:
评论

相关推荐

    信号灯模型线程实现方法

    信号灯模型是并发编程中的一种常见机制,常用于线程间的同步与通信。在系统级芯片(System-on-a-Chip, SOC)上实现信号灯模型,可以有效地协调多个任务或线程,确保资源的安全访问和避免竞态条件。在本案例中,我们...

    Linux多线程环境信号灯的使用

    在多线程环境中,信号灯(Semaphore)是一种同步机制,用于控制多个线程对共享资源的访问,避免竞态条件的发生。本文将深入探讨在Linux Red Hat 7.0环境下如何使用信号灯,并以提供的`test.c`源代码为例进行解析。 ...

    Linux信号灯C语言编程示例(包含信号灯回滚,信号等取值和初始化操作)

    在Linux系统编程中,信号灯(Semaphore)是...在多线程或多进程环境中,信号灯是解决竞态条件和死锁的有效工具。通过理解并正确使用`mysem.c`和`mysem.h`中的代码,开发者可以更好地控制并发访问,实现高效的程序设计。

    信号灯法实现生产者与消费者模式.rar

    "信号灯法"(也称为信号量或Semaphore)是一种有效的方法,用于解决生产者与消费者问题,这种模式在并发编程中非常常见。下面我们将深入探讨这个主题。 **生产者与消费者模式** 是一个经典的多线程问题,涉及到两个...

    Windows驱动编程视频教程-用户模式的事件与信号灯

    接下来,我们来看“信号灯”(Semaphore)。信号灯是另一种同步机制,它允许特定数量的线程访问一个共享资源。当信号灯计数值大于0时,线程可以获取一个许可证并进入临界区;当计数值为0时,其他试图获取许可证的...

    Linux环境下多线程编程及信号灯同步互斥应用指南

    此外,还探讨了如何使用 semaphore 实现进程间的同步与互斥,通过实例解析展示了经典的多线程和进程间通讯问题,如生产者消费者模型、信号灯的应用场景及解决办法。 适合人群:对于有一定Linux系统操作基础的学生...

    linux中一个程序的两个线程的同步(c语言实现)

    信号灯(Semaphore)是一种同步机制,用于控制多个线程访问共享资源的数量。信号灯可以设置一个初始值,表示可以访问资源的线程数量。当一个线程访问资源时,需要执行 P 操作(wait 操作),将信号灯的值减 1;当...

    java线程并发semaphore类示例

    Semaphore,顾名思义,就像是一个信号灯或通行证,用来管理一组有限的资源。在Java中,Semaphore类提供了对并发线程进行计数的许可管理,允许我们限制同时访问特定资源的线程数量。这在处理并发任务时非常有用,例如...

    多线程控制红绿灯变化

    在本场景中,“多线程控制红绿灯变化”是一个典型的并发编程问题,旨在模拟现实生活中交通信号灯的交替工作模式。这个系统设计通常涉及两个主要线程,一个负责控制红灯,另一个负责控制绿灯,它们需要按照特定的时间...

    2.线程间同步和通信之信号量(静态)

    在点灯示例中,可能有多个线程试图控制LED灯。通过使用信号量,我们可以确保每次只有一个线程能改变LED的状态,防止闪烁或混乱。线程A负责点亮LED,线程B负责熄灭LED。它们都会尝试获取信号量,只有成功获取到信号量...

    易语言-易语言多线程控制:信号量控制线程数量

    在多线程控制中,信号量是一个关键的概念,用于协调多个线程对共享资源的访问,从而避免了竞态条件和死锁等问题。本文将深入探讨易语言中的信号量控制线程数量这一主题。 首先,我们需要理解什么是线程。线程是程序...

    使用Java模拟交通信号灯.zip

    综上所述,这个Java交通信号灯模拟项目涵盖了多线程编程、并发控制、异常处理和单元测试等多个关键的Java编程知识点,是学习和实践Java技术的好案例。通过阅读和分析这个项目,开发者可以深入理解Java并发编程的核心...

    Posix多线程编程学习笔记

    信号灯(Semaphore) 信号灯是一种用于同步多个线程访问共享资源的数据结构。它可以控制多个线程对共享资源的访问顺序。Posix提供了两种类型的信号灯:二进制信号灯和计数信号灯。 - **二进制信号灯**:只有两种...

    操作系统课设报告.docx

    然后,报告详细介绍了使用多线程解决读者阅览问题的步骤,包括创建reader函数、使用信号灯判断座位是否被坐满、实现上锁操作、找座位坐下、阅读、打印座位信息、当前读者离开座位、读者注销等步骤。报告最后还对课程...

    linux多线程信号量.pdf

    在Dijkstra的模型中,信号如同铁路信号灯,控制着单线轨道上的火车通行。在计算机术语中,信号量是一个简单的整数值,线程通过P(prolagen,尝试减少)和V(verhogen,增加)操作来管理信号量,以确保对共享资源的...

    CenaFilosofos:使用交通信号灯解决哲学家的晚餐问题

    在现实生活中,交通信号灯通过红、黄、绿三种颜色的交替控制交通流,避免交通堵塞。在哲学家的晚餐问题中,我们可以将筷子看作是交通信号灯,通过设置状态来控制哲学家取放筷子的行为。 在CenaFilosofos项目中,每...

    多线程、许可证、互斥量、信号量 API的使用

    许可证,也称为信号灯或信号量,是多线程同步的一种机制,用于限制对共享资源的并发访问。它是一个整数值,当值为正时,表示可用许可证的数量;当值为零时,其他试图获取许可证的线程将被阻塞,直到有线程释放许可证...

    线程同步的一个小程序

    8. **Semaphore**:信号灯,可以控制同时访问特定资源的线程数量,与互斥量类似,但更灵活,可以控制多个线程同时访问。 在实际编程中,选择哪种同步机制取决于具体的需求。例如,如果需要确保某个资源只被一个线程...

    多线程线程

    常见的同步机制包括互斥量(Mutex)、信号量(Semaphore)、事件(Event)、临界区(Critical Section)以及线程局部存储(TLS)等。 3. **死锁**:当两个或更多线程相互等待对方释放资源时,就会发生死锁。避免...

    华科操作系统实验报告.doc

    - 信号灯(Semaphore):理解信号灯作为进程间通信(IPC)的一种工具,用于解决资源的互斥访问和同步问题。 #### 1.2 实验过程 - **预备知识**:复习线程的基本概念,如线程的生命周期、调度和同步。 - **实验测试...

Global site tag (gtag.js) - Google Analytics