Semaphore控制并发量

Semaphore作为synchronized的增强版,用于控制并发线程的数量,防止资源过载。它提供acquire()和release()方法来获取和释放许可,允许动态调整许可数量。Semaphore还支持公平与非公平模式,确保线程调度策略。此外,Exchanger用于线程间的数据交换,其exchange()方法在没有其他线程交换时会阻塞。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Semaphore 提供的功能是synchronized的升级版,可以实现对并发数量的控制。

  1. Semaphore 同步性
    acquire()方法获得一个许可,release()释放一个许可,Semaphore 可以控制获得许可的线程数量,让线程排队执行任务,保证不会出现非线程安全的问题。(需要控制构造Semaphore 时的参数permits=1)。

  2. Semaphore 常用API
    acquire(int permits) 指定获取许可个数。
    release(int permits)指定释放许可个数。
    注意: new Semaphore (5) 构造时的个数并不是最终许可个数,release(int permits)可以动态增加许可个数。
    acquireUninterruptibly() 使进入acquire()方法的线程,不允许被中断。获得锁后则取得指1个许可。
    acquireUninterruptibly(int permits)使进入acquire()方法的线程,不允许被中断。获得锁后则取得指定permits个数许可。
    availablePermits() 获得Semaphore 对象中当前可用的许可数。
    drainPermits() 获得Semaphore 对象中当前可用的许可数,并将可用许可数置0;
    getQueueLength() 取得等待许可的线程个数。
    hasQueuedThreads() 判断是否还有线程在等待许可。
    tryAcquire() 尝试获得一个许可,获取不到返回false,具有无阻塞的特点(不会导致获取不到就进入等待状态)。
    tryAcquire(int permits) 尝试获得指定permits个数许可,获取不到返回false,具有无阻塞的特点(不会导致获取不到就进入等待状态)。
    tryAcquire(long timeout, TimeUnit unit)在指定时间内尝试获得一个许可,获取不到返回false,具有无阻塞的特点(不会导致获取不到就进入等待状态)。
    tryAcquire(int permits, long timeout, TimeUnit unit)在指定时间内尝试获得指定permits个数许可,获取不到返回false,具有无阻塞的特点(不会导致获取不到就进入等待状态)。

  3. 公平与非公平信号量的测试
    公平信号量就是获得锁的顺序与启动线程的顺序有关(先启动先获得许可),非公平就无关。
    new Semaphore(1,true) 创建一个公平信号量。
    new Semaphore(1,false) 创建一个非公平信号量。

  4. Exchanger 线程间的通信
    exchange(String x) 方法具有阻塞特点,调用后会等待其他线程来取值,没有线程来取就一直等待。
    exchange(V x, long timeout, TimeUnit unit) 在指定时间内没有其他线程来取数据就抛出超时异常。
    exchange数据交换只能两两交换,若有三个线程就会出现一个线程交换不了数据而阻塞。

package semaphoreExchanger;

import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test1 {
	public static void main(String[] args) {
		ExecutorService service =Executors.newCachedThreadPool();
		final Exchanger exchanger = new Exchanger();
		service.execute(new Runnable() {
			 
			@Override
			public void run() {
				try{
					String data = "线程A的数据";
					System.out.println("线程"+Thread.currentThread().getName()+
							"正在把数据 "+data+" 换出去");
					Thread.sleep((long)Math.random()*10000);
					String data2 = (String)exchanger.exchange(data);
					System.out.println("线程 "+Thread.currentThread().getName()+
							"换回的数据为 "+data2);
				}catch(Exception e){
					e.printStackTrace();
				}
				
			}
		});
		
		service.execute(new Runnable() {
			
			@Override
			public void run() {
				try{
					String data1 = "钱";
					System.out.println("线程"+Thread.currentThread().getName()+
							"正在把数据 "+data1+" 交换出去");
					Thread.sleep((long)(Math.random()*10000));
					String data2 =(String)exchanger.exchange(data1);
					System.out.println("线程 "+Thread.currentThread().getName()+
							"交换回来的数据是: "+data2);
				}catch(Exception e){
					e.printStackTrace();
				}
				
				
			}
		});
		
		service.execute(new Runnable() {
			
			@Override
			public void run() {
				try{
					String data1 = "钱复合肥";
					System.out.println("线程"+Thread.currentThread().getName()+
							"正在把数据 "+data1+" 交换出去");
					Thread.sleep((long)(Math.random()*10000));
					String data2 =(String)exchanger.exchange(data1);
					System.out.println("线程 "+Thread.currentThread().getName()+
							"交换回来的数据是: "+data2);
				}catch(Exception e){
					e.printStackTrace();
				}
				
				
			}
		});
	}
 

}

线程pool-1-thread-1正在把数据 线程A的数据 换出去
线程pool-1-thread-2正在把数据 钱 交换出去
线程pool-1-thread-3正在把数据 钱复合肥 交换出去
线程 pool-1-thread-2交换回来的数据是: 线程A的数据
线程 pool-1-thread-1换回的数据为 钱

线程pool-1-thread-3三会一直阻塞,直到有线程跟他交换数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值