当前位置:网站首页>线程间控制之Semaphore使用介绍

线程间控制之Semaphore使用介绍

2022-04-23 14:07:00 pureluckyfish

        Semaphore(信号量)通常用于限制访问某些(物理或逻辑)资源线程的数量。

        一个信号量维护一组许可证。每个acquire()都会阻塞,直到获得许可证;每个release()会释放许可证。如果没有线程需要获取许可证;信号量只是像其它池对象那样保持一个可用许可证的计数。

        池对象:线程池、数据库连接池等,创建一个池子,池子中已经建立好了连接,需要使用的时候直接从池子中拿来用。

一、Pool类源代码

        例子,这里有一个Pool类,它使用信号量来控制对项目池的访问

package ThreadStudy;

import java.util.concurrent.Semaphore;
//信号量通常用于限制访问某些(物理或逻辑)资源线程的数量
public class Pool {
	private final static int MAX_AVAILABLE = 100;
	//创建一个具有100许可证的信号量,采用公平方式获取许可证
	private final Semaphore semaphore = new Semaphore(MAX_AVAILABLE, true);

	public Object getItem() throws Exception {
		semaphore.acquire();
		return getNextAvailableItem();
	}

	public void putItem(Object x) {
		if (markAsUnused(x)) {
			semaphore.release();
		}
	}
	// 管理的任何类型的项目
	Object[] items = new Object[MAX_AVAILABLE];
	boolean[] used = new boolean[MAX_AVAILABLE];

	protected synchronized Object getNextAvailableItem() {
		for (int i = 0; i < MAX_AVAILABLE; i++) {
			if (!used[i]) {
				used[i] = true;
				return items[i];
			}
		}
		return null;
	}

	protected synchronized boolean markAsUnused(Object item) {
		for (int i = 0; i < MAX_AVAILABLE; ++i) {
			if (item == items[i]) {
				if (used[i]) {
					used[i] = false;
					return true;
				} else {
					return false;
				}

			}
		}
		return false;
	}
}

二、二进制信号量用法

        一个初始化为1的信号量,并且它最多只能有一个permit可用,可以作为互斥锁。这通常被称为二进制信号量,因为它只有两种状态:一个可用的许可证,或零可用的许可证。当以这种方式使用时,二进制信号量具有这样的属性(与许多锁实现不同),即“锁”可以由所有者以外的线程释放(因为信号量没有所有权的概念)。这在某些特定的上下文中可能很有用,比如死锁恢复。

package ThreadStudy;

import java.util.concurrent.Semaphore;

public class SemaphoreT2 {
	public static void main(String[] args) throws Exception {
		Semaphore semophore = new Semaphore(1);
		semophore.acquire();
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					// 获取不到许可证,线程阻塞
					System.out.println(Thread.currentThread().getName()+"获取不到许可证,线程阻塞");
					semophore.acquire();
					System.out.println(Thread.currentThread().getName()+"获取到许可证,线程继续执行");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();

		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					// 释放许可证
					System.out.println(Thread.currentThread().getName()+"释放许可证");
					Thread.sleep(3000);
					semophore.release();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();

	}
}


三、Semaphore类中各种方法使用介绍

        1、俩个构造方法的区别,公平非公平!

Semaphore(int permits) 创建一个具有给定许可数和不公平设置的信号量
Semaphore(int permits, boolean fair) 创建一个具有给定许可数和给定公平性设置的信号量

        2、普通方法

获取许可证 释放许可证

acquire()

从这个信号量获得一个许可,阻塞直到一个可用,或者线程被中断

release()

释放一个许可证,将其返回给信号量

acquire(int permits)

从信号量获取给定数量的许可

release(int permits)

释放给定的许可证数量,将它们返回给信号量

acquireUninterruptibly()

从信号量获得一个许可,阻塞直到一个可用

acquireUninterruptibly(int permits)

从信号量获取给定数量的许可

tryAcquire()

获取到许可证返回true,获取不到返回false

tryAcquire(int permits)
tryAcquire(int permits, long timeout, TimeUnit unit)
tryAcquire(long timeout, TimeUnit unit)

        3、代码示例

package ThreadStudy;

import java.util.concurrent.Semaphore;

public class SemaphoreT1 {
	public static void main(String[] args) {
		int MAX = 10;
		// 创建10个许可证
		Semaphore s = new Semaphore(MAX);
		for (int i = 0; i < MAX; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {

						System.out.println("等待获取许可证的线程数量评估值:" + s.getQueueLength());
						// 获取二个许可证
						s.acquire(2);
						
						System.out.println("返回此信号量中可用的当前许可数,此方法通常用于调试和测试目的:" + s.availablePermits());
						System.out.println("获取并返回所有立即可用的许可:" + s.drainPermits());
						// 和acquire的唯一区别就是,一直处于阻塞状态,除了获取到一个许可证
						s.acquireUninterruptibly();

						// 获取许可证,并且返回true,便于代码流程控制
						if (s.tryAcquire()) {
							System.out.println("tryAcquire返回为true");
						} else {
							System.out.println("tryAcquire返回为false");
						}
						Thread.sleep(1000);
						// 获取一个许可证
						s.acquire();
						// 获取5个许可证
						s.acquire(5);

						System.out.println("线程获取到许可:" + Thread.currentThread().getName());
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}).start();
		}
	}
}

版权声明
本文为[pureluckyfish]所创,转载请带上原文链接,感谢
https://blog.csdn.net/sinat_33918956/article/details/122533983